プロンプト
マルチパーティ WebRTC 会議向けのブラウザ側エンドツーエンド暗号化を設計してください。メディアサーバーは RTP を転送しますが、音声や動画を読み取ってはなりません。送信側と受信側は Worker 内でエンコード済みフレームを処理します。RTCRtpScriptTransform、RTCRtpScriptTransformer、鍵配送、キーフレーム、パフォーマンス、障害復旧、および互換性について説明してください。エンコード済みフレームの変換とトランスポート TLS の違いを明確に区別してください。
面接官がテストしていること
この設問でテストされるのは、ブラウザのメディアパイプラインの境界を理解しているかどうかです。すなわち、エンコード後かつデコード前に変換を行うこと、readable から writable までのフレーム順序を維持すること、フレームごとの暗号処理を Worker に移行すること、鍵ローテーション、参加時のキーフレーム、フレームドロップ、および非対応ブラウザを適切に処理することです。フレームのライフサイクルに触れずに「RTP を暗号化する」とだけ答えるのは不十分です。
明確にすべき質問
- どの関係者をメディアサーバーから保護する必要があり、メディアサーバーはパケットの転送のみが許可されていますか?
- 画面共有や録音・録画とともに、音声も含まれますか?
- 鍵は認証されたエンドツーエンドシグナリングによって配布され、退出したメンバーはどのように失効されますか?
- どのブラウザマトリックスがサポートされますか?非対応クライアントは拒否、ダウングレード、または E2EE 無効化のいずれにすべきですか?
30秒のフレームワーク
TLS はトランスポートリンクを保護しますが、メディアサーバーが平文を見るのを防ぐことはできません。E2EE は送信側のエンコーダーの後に暗号化し、受信側のデコーダーの前に復号します。機能検出、Worker フレームパイプライン、鍵とナンス、キーフレームと再試行、ダウングレード/可観測性の 5 つのレイヤーを網羅します。MDN はこの API を Baseline 2025 と位置付けていますが、ブラウザマトリックスのテストは依然として必要です。
ステップバイステップの設計
1. 機能の検出と早期のアタッチ
Worker、方向マーカー、および転送可能な MessagePort を使用して RTCRtpScriptTransform を構築します。最初のフレームの前に、送信側では RTCRtpSender.transform に、受信側では RTCRtpReceiver.transform にアタッチします。機能チェックの失敗は明示的な状態であり、平文メディアのまま暗黙的に成功させてはなりません。
2. Worker でのフレーム処理
Worker は rtctransform を処理し、event.transformer.readable からエンコード済みフレームを読み取り、TransformStream を実行して event.transformer.writable に書き込みます。順序を維持し、各フレームを正確に 1 回だけキューに入れます。エラー時はストリームを閉じて状態を報告します。メインスレッドは設定と短寿命の鍵ハンドルを送信し、フレームごとの暗号化処理は行いません。
3. 暗号文と鍵の有効期間の定義
会議、送信者、および鍵エポックごとにコンテキストを作成します。フレームカウンターとストリーム識別子から、決して再利用されないナンスを導出します。暗号文にバージョン、エポック、および認証タグを含め、復号前に検証します。認証されたエンドツーエンドシグナリング経由で鍵を配布し、ローテーション中は短いデュアルエポックの重複を許容し、メンバーが退出した際には新しいフレームへのアクセスを失効させます。
4. キーフレームによる復旧
新規参加者はキーフレームの前にデルタフレームを受信する可能性があり、それをデコードできません。受信側の変換は、新しい鍵が到着した後やデコードが不可能になった後に sendKeyFrameRequest() を呼び出すことができます。送信側の変換は generateKeyFrame() を呼び出すことができます。どちらも Promise を返すため、方向とビデオの状態を確認し、リクエストのレート制限を行います。
5. レイテンシとメモリの予算管理
コピーとガベージコレクションを最小限に抑え、安全な場所ではフレームバッファを再利用し、Worker の並行性を制限内に保ちます。変換レイテンシ、キューの深さ、ドロップ率、およびキーフレーム要求率を測定します。暗号処理がレイテンシ予算を超える場合は、UI スレッドをブロックするのではなく、ビデオ品質を下げるかトラックを一時停止します。
6. エラーと再接続の処理
期限切れの鍵、認証の失敗、Worker のクラッシュ、および拒絶された API 呼び出しは、観測可能なステートマシンに入ります。一時的な障害の場合は Worker を再起動して現在のエポックを再開し、復旧に失敗した場合はトラックを停止して状態を説明します。PeerConnection の再ネゴシエーション後は、古い Worker が新しい送信者に追従すると仮定せず、新しい変換をアタッチします。
7. 互換性とセキュリティの境界設定
MDN は Encoded Transform を Baseline 2025 とラベル付けしていますが、古いブラウザやデバイスには存在しない場合があります。プロダクトポリシーとして、明示的に拒絶するか、E2EE を無効化するか、信頼できるメディアサーバーによるトランスコードを許可する必要があります。W3C ドキュメントは作業草案(Working Draft)であるため、インターフェースの安定性と実装の差異を展開計画で見える化しておく必要があります。
優れた回答例
「送信側エンコーダーの後、受信側デコーダーの前に RTCRtpScriptTransform をアタッチします。Worker は readable からエンコード済みフレームを読み取り、認証付き暗号を適用して writable に書き込みます。エンドツーエンドシグナリングが会議、メンバー、エポックごとに鍵を管理し、決して再利用されないフレームカウンターがナンスを形成し、受信側は復号前にタグを検証します。新しいメンバーや新しい鍵でデルタフレームをデコードできない場合、受信側は sendKeyFrameRequest をレート制限して実行し、送信側は generateKeyFrame を呼び出せます。変換レイテンシ、キュー深度、ドロップ、および認証失敗を測定し、復旧に失敗した場合はトラックを停止します。機能検出によって拒絶、ダウングレード、または E2EE 無効化を選択し、ロールアウトでは Baseline 2025 と W3C Working Draft のステータスを記録します。」
よくある失敗パターン
- TLS をメディアのエンドツーエンド暗号化と混同すること。
- メインスレッド上ですべてのフレームを暗号化したり、エンコード済みフレームではなく未加工フレームを変換したりすること。
- ナンスの再利用、認証チェックの省略、またはエポックや失効処理の省略。
- キーフレーム、Worker のクラッシュ、再接続、およびブラウザ間の差異を無視すること。
- Encoded Transform インターフェースを確認せずに WebRTC サポートを主張すること。
フォローアップの方向性
なぜエンコード後に変換するのですか?
エンコード済みフレームの方がサイズが小さく、RTP パイプライン内に留まるためです。未加工フレームの変換は、エンコード前に追加のコピーや計算を発生させます。
sendKeyFrameRequest() は常にリクエストを送信しますか?
いいえ。ユーザーエージェントは Promise を履行(fulfill)しつつも、不要と判断する場合があります。そのため、プロダクト側で待機とタイムアウトの処理が必要です。
鍵はどのように Worker に渡すべきですか?
options または転送可能な MessageChannel 経由で短寿命のハンドルを渡します。長寿命の鍵が無関係なスクリプトに露出しないようにします。
非対応ブラウザでサイレントにダウングレードしてもよいですか?
いいえ。現在のメディアが E2EE であるかどうかを、ユーザーおよび会議ポリシーで明確に示す必要があります。
サーバーが平文を見ていないことをどう証明しますか?
テスト環境の転送ノードでデータをキャプチャし、暗号文フレームのみが見えていることを検証します。また、シグナリング、Worker、鍵サービス、および録画権限を監査します。
参考文献
MDN “Using WebRTC Encoded Transforms”、MDN “RTCRtpScriptTransformer”、および W3C “WebRTC Encoded Transform” Working Draft。