tapeshelfが動画を暗号化する仕組みと、鍵を保存しない理由

tapeshelfの非公開動画を見られるのは、持ち主と、持ち主が選んだ人だけです。アプリがそれをどう守っているのか、そして保護がどこで終わるのかを説明します。
アップロードから配信まで
ブラウザはファイルを、S3互換ストレージの非公開バケットへ直接アップロードします。16MBずつのパートに分けて送るので、接続が切れても途中から再開できます。ファイルが私たちのAPIサーバーを経由することはありません。
バックグラウンドのワーカーがffprobeでファイルを確認し、メタデータ(撮影場所と日時、カメラ、作成者、コメント)を取り除きます。再エンコードはせず、ファイルを書き直すだけです。ダウンロードされるのは、こうして整えたファイルです。2026年10月18日より前にアップロードされた動画には、メタデータが残っています。
1080pまでのH.264動画で、ほかにいくつかの確認を通ったものは、パッケージし直すだけなので数秒で終わります。それ以外は1080pまでのH.264に変換します。その結果をffmpegが6秒ずつのHLSセグメントに切り分けます。Safariはこれをそのまま再生し、ほかのブラウザはhls.jsを通して再生します。
セグメントの暗号化
ffmpeg自体にもHLSを暗号化する機能はありますが、鍵をディスク上のファイルとして渡す必要があります。鍵をどのディスクにも置きたくなかったので、セグメントの暗号化はワーカーが自分で行います。
- 各セグメントは、HLSの規格が定めるとおりCBCモードのAES-128で暗号化します。
- 鍵は16バイトで動画ごとに異なり、ワーカーが処理している間だけそのメモリ上に存在します。
- 初期化ベクトルにはセグメントの通し番号を使います。プレイリストで指定がないとき、HLSプレイヤーが前提にする値です。
非公開バケットに送るのは、暗号化したセグメントとそのプレイリストだけです。ワーカーの一時ファイルは、処理が終わると削除します。
保存されない鍵
処理が終わったあと、鍵はどこにも残りません。ランダムな鍵を作って厳重に保管する代わりに、tapeshelfは必要になるたびに鍵を導出します。
動画の鍵 = HKDF-SHA256(マスターキー, "video:" + 動画ID + バージョン) → 16バイト
動画を編集するとバージョンが上がり、鍵も新しくなります。
マスターキーは、サーバーの設定にある1つのシークレットです。データベースにも、バケットにも、バックアップにも入っていません。データベースのコピーには動画の鍵が1つもなく、バケットにあるのは暗号化されたセグメントだけです。攻撃者はサーバーの設定まで手に入れる必要があります。
マスターキーをなくすと、どの動画も二度と再生できなくなり、データベースのバックアップがあっても元に戻せません。tapeshelfを自分のサーバーで運用する場合は、特に注意してください。
再生ボタンを押したときの3つのリクエスト
- 再生の開始。 APIは、視聴してよいかを確認します。投稿者本人であるか、動画が自分の棚にあるか、公開動画であるかです。問題がなければ、署名付きトークンを含むプレイリストのアドレスを返します。トークンには動画と視聴者(ログインしていなければ「誰でもない」)が記録され、1時間有効です。
- プレイリスト。 APIはトークンとアクセス権をもう一度確認し、プレイリストをその場で書き換えます。各セグメントはストレージへの署名付きリンクになり、鍵の行はAPIを指します。
- 鍵。 トークンはこの動画に対して発行されたものでなければなりません。非公開動画の場合は、ログイン中のセッションもトークンに記録された人のものである必要があります。ここまで確認できて初めて、APIが鍵を導出し、16バイトを返します。
期限付きリンクには確認すべきアカウントがないので、そのページではトークンがリンク自体を指します。リクエストのたびに、リンクがまだ有効か、動画がまだリンクに含まれているかを確認します。トークンがリンクより長く有効になることはありません。ゲストが交換で受け取った動画も、同じ仕組みで交換ページで1週間再生できます。
アクセスの判定は1分間キャッシュします。2時間の映画で、リクエストのたびにデータベースへ問い合わせずに済むようにするためです。削除された動画は、この1分の間ならまだ再生を始められます。期限切れになった期限付きリンクや無効にされた期限付きリンクは、すぐに使えなくなります。どちらの場合も、すでに再生中のプレイヤーは鍵とセグメントのリンクを持っているので、そのまま再生を続けることがあります。
セグメントのリンクにも署名があり、1時間以上たつと期限が切れます。プレイヤーはプレイリストを一度しか読み込まないため、リンクが短すぎると一時停止しただけで再生できなくなってしまいます。リンクの期限が切れると、プレイヤーは再生をあらためてリクエストし、同じ位置から続けます。そもそも鍵がなければ、セグメントだけを手に入れても役に立ちません。
持ち出せるファイルがない理由
プレイヤーが動画ファイルへのリンクを受け取ることはありません。渡されるのは、トークンに結びついたプレイリスト、暗号化された断片、そして確認を通った人だけが受け取れる鍵です。非公開動画のプレイリストのアドレスを友達のブラウザに貼り付けても、何も再生されません。鍵にはあなたのセッションが必要だからです。
ダウンロードは別の仕組みです。ログインしている人は、視聴を許された動画をダウンロードできます。アカウントがない場合にダウンロードできるのは、誰かから送られた期限付きリンクの動画と、ゲストとして交換で受け取った動画(1週間)だけです。ダウンロード用のリンクは2分間しか使えません。
画像の扱いは異なります。サムネイル、各動画から取った16コマ、それを並べたコマ割りプレビューは、推測できない長いランダムな名前で公開バケットに置かれ、バケットの一覧は取得できません。非公開動画のプレビューが見えるのは意図したものです。訪問者は、それを見て何をリクエストするのかを判断します。
防げること
- アクセス権のない人には、プレイリストもセグメントも鍵も渡りません。
- セグメントのリンクが漏れても、中身は暗号化されたノイズです。非公開動画のプレイリストのリンクが漏れても、発行された相手のセッションがなければ動かず、いずれにしても1時間以内に期限が切れます。
- データベースのコピーが盗まれても、鍵は1つも漏れません。
防げないこと
- 視聴できる人は録画もできます。 アクセス権のある人は、画面を録画したり、適切なツールでストリームを保存したりできます。鍵は正当に渡されているからです。tapeshelfにはDRMがありません。WidevineやFairPlayのような本格的なDRMは商用のライセンスサーバーに依存しますし、それでも画面に向けたカメラは止められません。
- 共有した相手。 共有や交換をすると、相手の手元には消えないコピーが残り、相手はファイルをダウンロードできます。あなたが送った期限付きリンクを開いた人も、リンクが有効な間は同じです。その後ファイルがどうなるかは、私たちには管理できません。信頼できる人とだけ共有してください。
- サーバーそのもの。 これはエンドツーエンド暗号化ではありません。鍵を導出するのはサーバーなので、サーバーを運用する人はどの動画でも再生できます。tapeshelf.comでは私たちがそれにあたり、サービスの運営やモデレーションに必要なときには非公開動画を開きます。セルフホストのインスタンスでは、その管理者です。
要点はセキュリティのページにまとめています。私たちの説明を信じるより自分で確かめたい方のために、コードはオープンソースで公開しています。いずれ自分で動かすこともできます。