[解説] Opencast Paella PlayerにおけるStored XSSの技術的詳細とフロントエンド対策
はじめに: Stored XSSとは何か?
Webアプリケーションのセキュリティ脆弱性の一つであるXSS(クロスサイトスクリプティング)は、攻撃者が悪意のあるスクリプトをWebページに注入し、そのページを閲覧したユーザーのブラウザで実行させる攻撃手法です。XSSには大きく分けて「Reflected XSS」「DOM-based XSS」「Stored XSS」の3種類があります。今回解説する脆弱性は「Stored XSS」に分類されます。
Stored XSSは、攻撃者が永続的なストレージ(データベースなど)に悪意のあるスクリプトを保存し、そのデータがユーザーに表示される際にスクリプトが実行されるものです。一度システムに仕込まれると、そのデータを閲覧した全てのユーザーが攻撃の影響を受ける可能性があり、非常に危険度が高いとされています。
脆弱性の概要: Opencast Paella PlayerのXSS
今回報告された脆弱性 (GHSA-m6c8-jcw2-5r25 / CVE-2026-77615) は、動画管理システムOpencastに組み込まれている動画プレイヤー「Paella Player」の `engage-paella-player` モジュールに存在します。深刻度は「High」と評価されており、非管理者ユーザーであっても悪用できる点が特徴です。
具体的には、Paella PlayerがWebVTT (Web Video Text Tracks) や DFXP (Distribution Format Exchange Profile) 形式のキャプションを処理する際に、キャプションキューテキストの内容を適切にエスケープせずにDOM (Document Object Model) に書き込んでいました。これにより、キャプションテキスト内にHTMLタグやJavaScriptコードが埋め込まれていた場合、それがそのままブラウザ上で実行されてしまうという問題です。
影響を受けるバージョンは、Opencastのサポート対象リリースラインである 19.x および 20.x (加えて 18.x) です。デフォルト設定でこの脆弱性が存在し、特別な設定変更は不要でした。
技術的な詳細: なぜXSSが発生したのか?
この脆弱性の根本原因は、Paella Playerのキャプションレンダリングロジックにあります。キャプションキャンバスが `_captionsContainer.innerHTML += cue` という形で、ユーザーが提供したキャプションキューテキストをHTMLとしてDOMに直接追加していました。この際、追加される `cue` の内容がHTMLエスケープされていなかったため、任意のHTMLやJavaScriptコードが有効なDOM要素として解釈・実行されてしまいます。
さらに、以下の要因が脆弱性の悪化に寄与していました。
<ul><li><b>入力エスケープの欠如:</b> キャプションのアップロードから処理、表示に至るまで、どこかでHTMLエスケープ処理が行われていませんでした。</li><li><b>デフォルト設定での悪用可能性:</b> WebVTT/DFXPキャプションプラグインはデフォルトで有効であり、「Subtitles」のアップロードオプションもアクティブです。これにより、特別な設定なしに悪用可能な状態にありました。</li><li><b>セキュリティヘッダーの欠如:</b> OpencastはXSS対策として有効な Content-Security-Policy (CSP) や、MIMEタイプスニッフィングを防ぐ X-Content-Type-Options ヘッダーを設定していませんでした。これにより、注入されたスクリプトの実行が制限されませんでした。</li></ul>
非管理者ユーザーがXSSペイロードを含むWebVTTファイルをアップロードし、そのイベントを公開するだけで、匿名ユーザーを含む全ての閲覧者がキャプションを有効にした際にXSSが実行されるという、極めてシンプルな再現手順で悪用可能でした。
影響範囲と悪用のシナリオ
この脆弱性が悪用された場合、攻撃者は以下のことを実行できます。
<ul><li><b>JavaScriptの実行:</b> Opencastのオリジンで任意のJavaScriptコードを実行できます。</li><li><b>セッションハイジャック:</b> 閲覧者の認証セッション情報を窃取し、そのユーザーになりすますことが可能です。これには、講師や管理者アカウントのセッションも含まれます。</li><li><b>CSRFトークンの窃取:</b> クロスサイトリクエストフォージェリ(CSRF)攻撃に利用されるトークンを窃取し、ユーザーの意図しない操作をAPI経由で実行させることができます。</li><li><b>データ改ざん・窃取:</b> 閲覧者の権限でOpencast REST APIを呼び出し、データ(イベント情報、ユーザー情報など)の閲覧・改ざんを行う可能性があります。</li></ul>
特に懸念されるのは、コンテンツ作成権限を持つ非管理者ユーザーがこの脆弱性を悪用でき、そのペイロードが匿名ユーザーを含む多くの閲覧者に影響を与える点です。
フロントエンドエンジニアが学ぶべき教訓と対策
このOpencastの事例は、フロントエンド開発者が日常的に扱うDOM操作において、セキュリティをいかに考慮すべきかを浮き彫りにしています。以下に、私たちフロントエンドエンジニアが学ぶべき教訓と対策を挙げます。
今回の脆弱性の直接的な原因は、ユーザー入力(キャプションテキスト)をエスケープせずに `innerHTML` に設定したことです。`innerHTML` は非常に強力ですが、同時に最も危険なDOM操作APIの一つです。ユーザー入力や信頼できない外部ソースから取得した文字列を `innerHTML` に直接設定することは、XSSの温床となります。
代わりに、安全なDOM操作API (`textContent` など) を使用するか、どうしてもHTMLを挿入する必要がある場合は、必ず信頼できるサニタイズライブラリ(例: DOMPurify)を用いて危険なタグや属性を除去してから挿入するようにしましょう。Reactの `dangerouslySetInnerHTML` や Vueの `v-html` も同様に、細心の注意を払って使用し、必ずサニタイズ済みのHTMLを渡すべきです。
「全てのユーザー入力は信頼できない」という原則を徹底することが重要です。これはフロントエンドとバックエンドの両方に言えることです。
<ul><li><b>入力検証:</b> サーバー側で入力データが期待する形式や内容であるかを厳しく検証します。</li><li><b>出力エスケープ:</b> データベースから読み出したデータやユーザー提供のデータをHTMLとして表示する際は、必ずコンテキストに応じた適切なエスケープ処理を行います。テキストとして表示する場合はHTMLエスケープを、JavaScriptコードとして利用する場合はJavaScriptエスケープを施します。</li></ul>
サーバー側での設定になりますが、XSS攻撃の影響を軽減するためにセキュリティヘッダーを導入することが推奨されます。
<ul><li><b>Content-Security-Policy (CSP):</b> 実行可能なスクリプトのソースやインラインスクリプトの使用などを制限し、XSS攻撃によるスクリプト実行を困難にします。</li><li><b>X-Content-Type-Options: `nosniff`:</b> ブラウザがMIMEタイプを推測するのを防ぎ、意図しないスクリプトの実行を防ぎます。</li></ul>
今回のように、アプリケーションが利用している動画プレイヤーなどの外部ライブラリやフレームワークに脆弱性が発見されることがあります。npm audit や GitHub Dependabot などを用いて、常に利用している依存関係の脆弱性情報をチェックし、最新のセキュリティパッチが適用されたバージョンへ速やかにアップデートする体制を整えましょう。
まとめ
Opencast Paella PlayerのXSS脆弱性は、ユーザー入力を扱う際のセキュリティ意識の重要性を改めて示しています。特に、フロントエンド開発者にとって、`innerHTML` のようなDOM操作APIの安全性と、エスケープ処理の徹底は不可欠な知識です。
安全なWebアプリケーション開発のためには、常に最新のセキュリティ情報をキャッチアップし、開発プロセスにおいてセキュリティを考慮した設計・実装を心がけることが求められます。この事例が、皆さんの日々の開発におけるセキュリティ意識の向上に繋がれば幸いです。