多くのウェブ アプリケーションでは、ユーザーが管理するコンテンツを表示する必要があります。これは、ユーザーがアップロードした画像(プロフィール写真など)を配信する単純な場合もあれば、ユーザーが管理する HTML(ウェブ開発チュートリアルなど)をレンダリングする複雑な場合もあります。安全に実行することは常に困難であったため、ほとんどのタイプのウェブ アプリケーションに適用できる、簡単で安全なソリューションを見つけるために取り組んできました。
信頼できないコンテンツを分離するための従来のソリューション
ユーザーが管理するコンテンツを安全に配信するための従来のソリューションは、サンドボックス ドメインと呼ばれるものを使用することです。基本的な考え方は、アプリケーションのメイン ドメインが example.com の場合、信頼できないコンテンツはすべて exampleusercontent.com で配信できるということです。これら 2 つのドメインは クロスサイトであるため、exampleusercontent.com 上の悪意のあるコンテンツが example.com に影響を与えることはありません。
このアプローチを使用すると、画像、ダウンロード、HTML など、あらゆる種類の信頼できないコンテンツを安全に配信できます。画像やダウンロードにこれを使用する必要はないように思えるかもしれませんが、特に古いブラウザでは、コンテンツ スニッフィングのリスクを回避できます。
サンドボックス ドメインは業界全体で広く使用されており、長年にわたってうまく機能してきました。ただし、2 つの大きな欠点があります。
- アプリケーションでは、コンテンツへのアクセスを 1 人のユーザーに制限する必要があることが多く、認証と認可の実装が必要になります。サンドボックス ドメインは、メイン アプリケーション ドメインと Cookie を共有しないように意図的に設計されているため、安全に実行することは非常に困難です。認証をサポートするには、サイトが機能 URLに依存するか、サンドボックス ドメインに個別の認証 Cookie を設定する必要があります。後者の方法は、多くのブラウザでクロスサイト Cookie がデフォルトで制限されている現在のウェブでは特に問題になります。
- ユーザー コンテンツはメインサイトから分離されますが、他のユーザー コンテンツからは分離されません。これにより、悪意のあるユーザー コンテンツがサンドボックス ドメイン上の他のデータ(同一オリジン データの読み取りなど)を攻撃するリスクが生じます。
また、サンドボックス ドメインは、リソースが分離されたドメインに明確に分割されるため、フィッシングのリスクを軽減するのに役立ちます。
ユーザー コンテンツを配信するための最新のソリューション
ウェブは進化し、信頼できないコンテンツを配信するためのより簡単で安全な方法が登場しました。さまざまなアプローチがありますが、ここでは Google で使用している 2 つのソリューションについて説明します。
アプローチ 1: 非アクティブなユーザー コンテンツの配信
サイトで非アクティブなユーザー コンテンツ(HTML や JavaScript ではないコンテンツ、たとえば画像やダウンロード)のみを配信する必要がある場合は、分離されたサンドボックス ドメインを使用せずに安全に実行できるようになりました。主な手順は 2 つあります。
Content-Typeヘッダーは常に、すべてのブラウザでサポートされ、アクティブ コンテンツを含まない既知の MIME タイプに設定します。迷った場合は、application/octet-streamを選択すると安全です。- また、ブラウザがレスポンスを完全に分離するように、レスポンス ヘッダーを常に設定します。
| レスポンス ヘッダー | 目的 |
|---|---|
X-Content-Type-Options: nosniff |
コンテンツ スニッフィングを防ぐ |
Content-Disposition: attachment; filename="download" |
レンダリングではなくダウンロードをトリガーする |
Content-Security-Policy: sandbox |
別のドメインで配信されたかのようにコンテンツをサンドボックス化する |
Content-Security-Policy: default-src ‘none' |
JavaScript の実行(およびサブリソースの組み込み)を無効にする |
Cross-Origin-Resource-Policy: same-site |
ページがクロスサイトで組み込まれないようにする |
ヘッダーをこのように組み合わせることで、レスポンスはアプリケーションによってサブリソースとしてのみ読み込まれるか、ユーザーによってファイルとしてダウンロードされます。さらに、ヘッダーは CSP サンドボックス ヘッダーと default-src 制限により、ブラウザのバグに対する多層防御を提供します。全体として、この設定により、この方法で配信されたレスポンスがインジェクションや分離の脆弱性につながることはないという高い信頼性が得られます。
多層防御
提案されているソリューションは、一般的に XSS に対する十分な防御となりますが、追加のセキュリティ レイヤを提供するために適用できる追加の強化対策がいくつかあります。
- IE11 との互換性のために
X-Content-Security-Policy: sandboxヘッダーを設定します。 Content-Security-Policy: frame-ancestors 'none'ヘッダーを設定して、エンドポイントが埋め込まれないようにします。- 分離されたサブドメインでユーザー コンテンツをサンドボックス化します。
- 分離されたサブドメインでユーザー コンテンツを配信します(たとえば、Google では
product.usercontent.google.comなどのドメインを使用します)。 Cross-Origin-Opener-Policy: same-originとCross-Origin-Embedder-Policy: require-corpを設定して、クロスオリジン分離 を有効にします。
- 分離されたサブドメインでユーザー コンテンツを配信します(たとえば、Google では
アプローチ 2: アクティブなユーザー コンテンツの配信
アクティブ コンテンツ(HTML や SVG 画像など)を安全に配信することも、従来のサンドボックス ドメイン アプローチの弱点なしで行うことができます。
最も簡単な方法は、Content-Security-Policy: sandbox ヘッダーを利用して、ブラウザにレスポンスを分離するように指示することです。すべてのウェブブラウザがサンドボックス ドキュメントのプロセス分離を実装しているわけではありませんが、ブラウザのプロセスモデルの継続的な改善により、サンドボックス化されたコンテンツと埋め込みアプリケーションの分離が改善される可能性があります。SpectreJS と レンダラ侵害攻撃 が脅威モデルの範囲外にある場合は、CSP サンドボックスを使用することが十分なソリューションとなる可能性があります。
Google では、サンドボックス ドメインのコンセプトを最新化することで、信頼できないアクティブ コンテンツを完全に分離できるソリューションを開発しました。基本的な考え方は次のとおりです。
- パブリック サフィックス リストに追加される新しいサンドボックス ドメインを作成します。たとえば、
exampleusercontent.comを PSL に追加すると、foo.exampleusercontent.comとbar.exampleusercontent.comがクロスサイトになり、完全に分離されます。 *.exampleusercontent.com/shimに一致する URL はすべて、静的な shim ファイルにルーティングされます。この shim ファイルには、messageイベント ハンドラをリッスンし、受信したコンテンツをレンダリングする短い HTML と JavaScript のスニペットが含まれています。- これを使用するには、プロダクトで
$RANDOM_VALUE.exampleusercontent.com/shimへの iframe またはダイアログを作成し、postMessageを使用して、信頼できないコンテンツをレンダリング用の shim に送信します。 - レンダリングされたコンテンツは Blob に変換され、 サンドボックス化された iframe 内にレンダリングされます。
従来のサンドボックス ドメイン アプローチと比較して、これにより、すべてのコンテンツが固有のサイトで完全に分離されます。また、レンダリングするデータの取得をメイン アプリケーションが行うため、機能 URL を使用する必要がなくなります。
まとめ
この 2 つのソリューションを組み合わせることで、googleusercontent.com などの従来のサンドボックス ドメインから、サードパーティ Cookie
のブロックと互換性のあるより安全なソリューションに移行できます。Google では、すでに多くのプロダクトでこれらのソリューションを使用するように移行しており、来年もさらに移行する予定です。