3. Principles of the Same-Origin Policy (同一生成元ポリシーの原則)
3. Principles of the Same-Origin Policy (同一生成元ポリシーの原則)
多くのユーザーエージェント (user agent) は, リモートの当事者に代わってアクションを実行します。例えば, HTTP ユーザーエージェントはリダイレクト (redirect) に従いますが, これはリモートサーバーからの指示であり, HTML ユーザーエージェントはリモートサーバーから取得したスクリプトに対して豊富なドキュメントオブジェクトモデル (Document Object Model, DOM) インターフェースを公開します。
セキュリティモデルがない場合, ユーザーエージェントはユーザーまたは他の当事者に有害なアクションを実行する可能性があります。時間の経過とともに, 多くのWeb関連技術は, 一般的に「同一生成元ポリシー (same-origin policy)」として知られる共通のセキュリティモデルに収束してきました。このセキュリティモデルは主に有機的に進化しましたが, 同一生成元ポリシーはいくつかの重要な概念の観点から理解できます。このセクションでは, これらの概念を提示し, これらの概念を安全に使用する方法についてのアドバイスを提供します。
3.1 Trust (信頼)
同一生成元ポリシーは, URIによって信頼関係を指定します。例えば, HTMLドキュメントは, URIを使用して実行するスクリプトを指定します:
<script src="https://example.com/library.js"></script>
ユーザーエージェントがこの要素を処理すると, ユーザーエージェントは指定されたURIでスクリプトを取得し, ドキュメントの特権 (privilege) でスクリプトを実行します。このようにして, ドキュメントは, URIによって指定されたリソースに, 所有しているすべての特権を付与します。本質的に, ドキュメントは, そのURIから取得された情報の完全性 (integrity) を信頼することを宣言します。
URIからライブラリをインポートすることに加えて, ユーザーエージェントは, URIによって指定されたリモートの当事者に情報を送信します。例えば, HTML formエレメントを考えてみましょう:
<form method="POST" action="https://example.com/login">
... <input type="password"> ...
</form>
ユーザーがパスワードを入力してフォームを送信すると, ユーザーエージェントはURIによって指定されたネットワークエンドポイントにパスワードを送信します。このようにして, ドキュメントはその秘密データをそのURIにエクスポートし, 本質的にそのURIに送信される情報の機密性 (confidentiality) を信頼することを宣言します。
3.1.1 Pitfalls (落とし穴)
同一生成元ポリシーを使用する新しいプロトコルを設計するときは, 重要な信頼の区別がURIで見えるようにしてください。例えば, トランスポート層セキュリティ (Transport Layer Security, TLS) と非TLS保護されたリソースの両方が "http" URIスキームを使用する場合 ([RFC2817]のように), ドキュメントはTLSを介してのみスクリプトを取得したいということを指定できません。"https" URIスキームを使用することで, ドキュメントはアクティブなネットワーク攻撃者から保護されたリソースと対話したいことを示すことができます。
3.2 Origin (生成元)
原則として, ユーザーエージェントはすべてのURIを個別の保護ドメイン (protection domain) として扱い, 1つのURIから取得されたコンテンツが別のURIと相互作用するために明示的な同意を要求することができます。残念ながら, この設計は開発者にとって煩雑です。なぜなら, Webアプリケーションは通常, 協調して動作する多数のリソースで構成されているからです。
代わりに, ユーザーエージェントはURIを「生成元 (origin)」と呼ばれる保護ドメインにグループ化します。大まかに言えば, 2つのURIが同じスキーム (scheme), ホスト (host), ポート (port) を持っている場合, それらは同じ生成元の一部です (つまり, 同じプリンシパル, principal を表します)。(詳細については, セクション4を参照してください。)
質問: なぜホスト (host) だけを使用しないのですか?
回答: 生成元タプル (origin tuple) にスキーム (scheme) を含めることは, セキュリティにとって不可欠です。ユーザーエージェントがスキームを含めなかった場合, http://example.com と https://example.com の間に分離はありません。なぜなら, 2つは同じホストを持っているからです。しかし, この分離がなければ, アクティブなネットワーク攻撃者は http://example.com から取得されたコンテンツを破損させ, そのコンテンツにユーザーエージェントに https://example.com から取得されたコンテンツの機密性と完全性を損なわせることができ, TLS [RFC5246] が提供する保護をバイパスします。
質問: なぜ「トップレベル」ドメインだけでなく完全修飾ドメイン名 (fully qualified domain name) を使用するのですか?
回答: DNSには階層的な委任 (hierarchical delegation) がありますが, ホスト名間の信頼関係は展開によって異なります。例えば, 多くの教育機関では, 学生は https://example.edu/~student/ でコンテンツをホストできますが, それは学生が作成したドキュメントが https://grades.example.edu/ でホストされている成績管理Webアプリケーションと同じ生成元の一部である (つまり, 同じ保護ドメインに存在する) べきであることを意味しません。
example.edu の展開は, 生成元によるリソースのグループ化がすべての展開シナリオと完全に一致するわけではないことを示しています。この展開では, すべての学生のWebサイトが同じ生成元に存在します, これは望ましくない可能性があります。ある意味で, 生成元の粒度 (origin granularity) は, セキュリティモデルがどのように進化したかの歴史的な産物です。
3.2.1 Examples (例)
次のすべてのリソースは同じ生成元を持っています:
http://example.com/
http://example.com:80/
http://example.com/path/file
各URIは同じスキーム, ホスト, ポートコンポーネントを持っています。
次の各リソースの生成元は, 他のリソースとは異なります:
http://example.com/
http://example.com:8080/
http://www.example.com/
https://example.com:80/
https://example.com/
http://example.org/
http://ietf.org/
各ケースで, スキーム, ホスト, ポートコンポーネントの少なくとも1つがリスト内の他のコンポーネントとは異なります。
3.3 Authority (権限)
ユーザーエージェントはURIを生成元にグループ化しますが, 生成元内のすべてのリソースが同じ権限 (authority) を持っているわけではありません (「権限」という言葉のセキュリティ上の意味であり, [RFC3986] の意味ではありません)。例えば, 画像はパッシブコンテンツ (passive content) であるため, 権限を持ちません, つまり, 画像はその生成元で利用可能なオブジェクトとリソースにアクセスできません。対照的に, HTMLドキュメントはその生成元の完全な権限を持ち, ドキュメント内の (またはドキュメントにインポートされた) スクリプトは, その生成元内のすべてのリソースにアクセスできます。
ユーザーエージェントは, リソースのメディアタイプ (media type) を調べることで, リソースにどれだけの権限を付与するかを決定します。例えば, メディアタイプが image/png のリソースは画像として扱われ, メディアタイプが text/html のリソースはHTMLドキュメントとして扱われます。
信頼できないコンテンツ (ユーザー生成コンテンツなど) をホストする場合, Webアプリケーションは, そのコンテンツのメディアタイプを制限することで, そのコンテンツの権限を制限できます。例えば, ユーザー生成コンテンツを image/png として提供することは, text/html として提供するよりもリスクが低くなります。もちろん, 多くのWebアプリケーションはHTMLドキュメントに信頼できないコンテンツを組み込んでいます。慎重に行わないと, これらのアプリケーションは, 信頼できないコンテンツにその生成元の権限を漏らすリスクがあります, これは一般的にクロスサイトスクリプティング (cross-site scripting) として知られる脆弱性です。
3.3.1 Pitfalls (落とし穴)
Webプラットフォームの新しい部分を設計する際には, メディアタイプに関係なくリソースに権限を付与しないように注意してください。多くのWebアプリケーションは, 制限されたメディアタイプで信頼できないコンテンツを提供しています。これらのコンテンツに権限を付与する新しいWebプラットフォーム機能は, 既存のアプリケーションに脆弱性を導入するリスクがあります。代わりに, すでに生成元の完全な権限を持っているメディアタイプ, または新しい権限を運ぶために特別に設計された新しいメディアタイプに権限を付与することを優先してください。
誤ったメディアタイプを提供するサーバーとの互換性を保つために, 一部のユーザーエージェントは「コンテンツスニッフィング (content sniffing)」を採用し, サーバーが提供したメディアタイプとは異なるメディアタイプを持っているかのようにコンテンツを扱います。慎重に行わないと, コンテンツスニッフィングはセキュリティの脆弱性につながる可能性があります。なぜなら, ユーザーエージェントは, 画像などの低権限メディアタイプに, HTMLドキュメントなどの高権限メディアタイプの特権を付与する可能性があるからです [SNIFF]。
3.4 Policy (ポリシー)
一般的に, ユーザーエージェントは異なる生成元を分離し, 生成元間の制御された通信を許可します。ユーザーエージェントが分離と通信を提供する方法の詳細は, いくつかの要因によって異なります。
3.4.1 Object Access (オブジェクトアクセス)
ユーザーエージェントによって公開されるほとんどのオブジェクト (アプリケーションプログラミングインターフェースまたはAPIとも呼ばれます) は, 同じ生成元でのみ利用可能です。具体的には, 1つのURIから取得されたコンテンツが別のURIから取得されたコンテンツに関連付けられたオブジェクトにアクセスできるのは, 2つのURIが同じ生成元に属している場合, つまり, 同じスキーム, ホスト, ポートを持っている場合のみです。
この一般的なルールにはいくつかの例外があります。例えば, HTMLのLocationインターフェースの一部は, 生成元を超えて利用可能です (例えば, 他のブラウジングコンテキスト, browsing contextをナビゲートできるようにするため)。別の例として, HTMLのpostMessageインターフェースは, クロスオリジン通信を促進するために明示的に生成元を超えて表示されます。外部の生成元にオブジェクトを公開することは危険であり, そうすることでこれらのオブジェクトを潜在的な攻撃者に公開するため, 非常に慎重に行う必要があります。
3.4.2 Network Access (ネットワークアクセス)
ネットワークリソースへのアクセスは, リソースがアクセスしようとするコンテンツと同じ生成元にあるかどうかによって異なります。
一般的に, 別の生成元から情報を読み取ることは禁止されています。ただし, 生成元は他の生成元から取得された特定の種類のリソースを使用することが許可されています。例えば, 生成元はスクリプトを実行したり, 画像をレンダリングしたり, 任意の生成元からスタイルシートを適用したりすることが許可されています。同様に, 生成元は, HTMLフレーム内のHTMLドキュメントなど, 別の生成元からのコンテンツを表示できます。ネットワークリソースは, 例えば, クロスオリジンリソース共有 (Cross-Origin Resource Sharing, CORS) [CORS] を使用して, 他の生成元がその情報を読み取れるようにすることもできます。これらの場合, 通常, アクセスは生成元ごとに付与されます。
別の生成元に情報を送信することは許可されています。ただし, 任意の形式でネットワーク経由で情報を送信することは危険です。このため, ユーザーエージェントは, カスタムヘッダーなしのHTTPリクエストなど, 特定のプロトコルを使用してドキュメントが情報を送信することを制限します。許可されたプロトコルのセットを拡張すること, 例えば, WebSocketのサポートを追加することは, 脆弱性を導入しないように慎重に行う必要があります [RFC6455]。
3.4.3 Pitfalls (落とし穴)
ユーザーエージェントが1つの生成元が別の生成元からのリソースと相互作用することを許可する場合は常に, セキュリティの問題が発生します。例えば, 別の生成元から画像を表示する機能は, その高さと幅を漏らします。同様に, 別の生成元にネットワークリクエストを送信する機能は, クロスサイトリクエストフォージェリ (cross-site request forgery, CSRF) の脆弱性を引き起こします [CSRF]。ただし, ユーザーエージェントの実装者は, これらのリスクとクロスオリジン相互作用を許可する利点とのバランスをとることがよくあります。例えば, クロスオリジンネットワークリクエストをブロックするHTMLユーザーエージェントは, ユーザーがハイパーリンクをたどることを妨げます, これはWebの中核機能です。
Webプラットフォームに新しい機能を追加する際に, 1つのリソースに特権を付与しながら, 同じ生成元内の別のリソースからその特権を差し控えることが魅力的である場合があります。ただし, この方法で特権を差し控えることは効果がありません。なぜなら, ユーザーエージェントは生成元内のリソースを分離しないため, 特権のないリソースは通常, とにかくその特権を取得できるからです。代わりに, 特権は生成元全体に付与または差し控えるべきです (生成元内の個々のリソースを区別するのではなく) [BOFGO]。
3.5 Conclusion (結論)
同一生成元ポリシーは, URIを使用して信頼関係を指定します。URIは生成元にグループ化され, 生成元は保護ドメインを表します。生成元内の一部のリソース (アクティブコンテンツ, active content など) には生成元の完全な権限が付与されますが, 生成元内の他のリソース (パッシブコンテンツ, passive content など) には生成元の権限が付与されません。その生成元の権限を運ぶコンテンツには, 自身の生成元内のオブジェクトとネットワークリソースへのアクセスが許可されます。このコンテンツには, 他の生成元のオブジェクトとネットワークリソースへの限定的なアクセスも許可されますが, これらのクロスオリジン特権は, セキュリティの脆弱性を回避するために慎重に設計する必要があります。