同一生成元ポリシーによって、ある生成元から読み込まれた文書やスクリプトが、異なる生成元からの文書のプロパティを取得したり設定したりするのを防ぎます。これは、潜在的に悪意のある文書を隔離するための重要なセキュリティメカニズムです。
生成元の定義
もしプロトコル、(与えられていれば) ポート、及びホストが両方のページで同じならば、二つのページが同一生成元を持っていると見なします。説明するために、以下の表では URL https://store.company.com/dir/page.html
との生成元の比較の例を挙げています。
URL | 結果 | 理由 |
---|---|---|
https://store.company.com/dir2/other.html |
成功 | |
https://store.company.com/dir/inner/another.html |
成功 | |
https://store.company.com/secure.html |
失敗 | 異なるプロトコル |
https://store.company.com:81/dir/etc.html |
失敗 | 異なるポート |
https://news.company.com/dir/other.html |
失敗 | 異なるホスト |
file:
URL の生成元の定義もご覧ください。
生成元の継承
about:blank
、javascript:
、data:
URL のコンテンツは、それらの URL を読み込んだ文書から生成元を継承します。これは、URL 自体には生成元の情報がないためです。
IE の例外事項
Internet Explorer には、同一生成元ポリシーについて 2 つの大きな例外があります。
- 信頼済みゾーン: 双方のドメインが高く信頼されたゾーン (企業のドメインなど) である場合は、同一生成元の制限を適用しません。
- ポート: IE は同一生成元の要素にポートを含みません。従って、https://company.com:81/index.html と https://company.com/index.html は同一生成元とみなし、制限を適用しません。
これらの例外事項は非標準であり他のブラウザではサポートしていませんが、Windows RT や IE ベースの Web アプリケーションを開発する場合は役に立つでしょう。
生成元の変更
ページの生成元は、いくつかの制限のもとに変更することができます。スクリプトは {{domxref("document.domain")}} の値を、現在のドメインまたは上位ドメインに設定できます。もしスクリプトによって現在のドメインの上位ドメインに設定されたら、より短いドメインは次の生成元のチェックのために使われます。例えば、https://store.company.com/dir/other.html
にある文書内のスクリプトが以下の命令文を実行したと想定します:
document.domain = "company.com";
この命令文の設定後、ページは https://company.com/dir/page.html
で生成元のチェックを通ることができます (許可を望むことを示すために https://company.com/dir/page.html
が自身の document.domain
を "company.com
" に設定すると仮定します。詳しくは {{domxref("document.domain")}} をご覧ください)。しかし、company.com
は document.domain
を othercompany.com
に設定することはできません。company.com
の上位ドメインではないためです。
ポート番号はブラウザにより、別に保持されます。document.domain = document.domain
を含むどのような設定の呼び出しでも、ポート番号は null
で上書きされます。従って始めに document.domain = "company.com"
を設定しただけでは、company.com:8080
と company.com
が交流することはできません。双方のポート番号が null
になるように、双方で設定しなければなりません。
注記: サブドメインが親ドメインへ安全にアクセスできるようにするために document.domain
を使用するときは、親ドメインとサブドメインの双方で document.domain
に同じ値を設定することが必要です。これは、単に親ドメインを元の値に戻す設定を行う場合でも必要です。これを怠るとパーミッションエラーが発生するでしょう。
異なる生成元へのネットワークアクセス
同一生成元ポリシーは {{domxref("XMLHttpRequest")}} や {{htmlelement("img")}} 要素を使用する場合など、2 つの生成元間の対話を制御します。これらの対話は一般的に、3 つのカテゴリに分けられます:
- 異なる生成元への書き込みは、概して許可されます。例えばリンク、リダイレクトやフォームの送信です。まれに使用される HTTP リクエストでは、プリフライトが必要です。
- 異なる生成元の埋め込みは、概して許可されます。例は後述します。
- 異なる生成元からの読み込みは概して許可されませんが、埋め込みによって読み込みアクセスはしばしば漏れ出します。例えば埋め込み画像の幅や高さ、埋め込みスクリプトのアクション、あるいは埋め込みリソースで可能なものを読み取ることが可能です。
以下に、異なる生成元で埋め込むことが可能なリソースの例を挙げます:
<script src="..."></script>
による JavaScript。構文エラーのエラーメッセージは、同一生成元のスクリプトについてのみ利用可能です。<link rel="stylesheet" href="...">
による CSS。CSS の寛大な構文規則のため、生成元を越える CSS は適切なContent-Type
ヘッダが必要です。制約はブラウザにより異なります: IE (日本語訳)、Firefox (日本語訳)、Chrome、Safari (日本語訳) (CVE-2010-0051 までスクロールしてください)、Opera。- {{htmlelement("img")}} による画像。サポートされる画像形式は PNG、JPEG、GIF、BMP、SVG などです。
- {{htmlelement("video")}} および {{htmlelement("audio")}} によるメディアファイル。
<object>
、<embed>
および<applet>
によるプラグイン。@font-face
によるフォント。異なる生成元のフォントを許可するブラウザもありますが、同一生成元のフォントを要求するブラウザもあります。<frame>
および<iframe>
によるものは何でも。このような方式による異なる生成元との対話を防ぐために、サイトでX-Frame-Options
ヘッダを使用できます。
異なる生成元とのアクセスを許可する方法
異なる生成元とのアクセスを許可するには、CORS を使用します。
異なる生成元とのアクセスをブロックする方法
- 異なる生成元への書き込みを防ぐには、リクエスト内の推測できないトークン (Cross-Site Request Forgery (CSRF) トークンとして知られる) をチェックして、このトークンを知っているページの、異なる生成元からの読み込みを止めなければなりません。
- 異なる生成元のリソースの読み込みを防ぐには、そのリソースを埋め込みできないようにします。リソースの埋め込みによって漏えいする情報があるため多くの場合、埋め込みの抑止が必要になります。
- 異なる生成元からの埋め込みを防ぐには、リソースが前出の埋め込み可能な形式であると判断されないようにしてください。ほとんどの場合、ブラウザは
Content-Type
を尊重しません。例えば<script>
タグで HTML ドキュメントを指した場合、ブラウザは HTML を JavaScript としてパースしようとします。リソースがサイトの入り口ではない場合は、埋め込みを抑止するため CSRF トークンも使用するとよいでしょう。
異なる生成元へのスクリプト API アクセス
iframe.contentWindow
、{{domxref("window.parent")}}、{{domxref("window.open")}}、{{domxref("window.opener")}} といった JavaScript API は、ドキュメントが互いに直接参照することを可能にします。2 つのドキュメントが同一の生成元ではないとき、これらの参照は次の 2 つのセクションで示すとおり、Window
オブジェクトや Location
オブジェクトへの限られたアクセスを提供します。
生成元が異なるドキュメント間でさらに通信するために、{{domxref("window.postMessage")}} を使用することができます。
Window
仕様書: https://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#security-window
以下の Window
のプロパティは、異なる生成元のアクセスが許可されています:
メソッド |
---|
{{domxref("window.blur")}} |
{{domxref("window.close")}} |
{{domxref("window.focus")}} |
{{domxref("window.postMessage")}} |
属性 | |
---|---|
{{domxref("window.closed")}} | 読み取りのみ |
{{domxref("window.frames")}} | 読み取りのみ |
{{domxref("window.length")}} | 読み取りのみ |
{{domxref("window.location")}} | 読み取り/書き込み |
{{domxref("window.opener")}} | 読み取りのみ |
{{domxref("window.parent")}} | 読み取りのみ |
{{domxref("window.self")}} | 読み取りのみ |
{{domxref("window.top")}} | 読み取りのみ |
{{domxref("window.window")}} | 読み取りのみ |
一部のブラウザは、仕様書が定めるものより多くのプロパティでアクセスを許可しています。
Location
仕様書: https://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#security-location
以下の Location
のプロパティは、異なる生成元のアクセスが許可されています:
メソッド |
---|
{{domxref("location.replace")}} |
属性 | |
---|---|
{{domxref("URLUtils.href")}} | 書き込みのみ |
一部のブラウザは、仕様書が定めるものより多くのプロパティでアクセスを許可しています。
異なる生成元へのデータストレージアクセス
localStorage や IndexedDB など、ブラウザ内部に保管されるデータへのアクセスは、生成元によって分けています。それぞれの生成元が個別にストレージを持ち、ある生成元の JavaScript が別の生成元に属するストレージを読み書きすることはできません。
Cookie では、生成元の定義が異なっています。ページは自身のドメインまたは任意の親ドメイン (親ドメインが public suffix ではない場合に限る) 用の Cookie を設定できます。Firefox や Chrome は Public Suffix List を使用して、ドメインが public suffix であるかを判断します。Internet Explorer は独自の方式により、ドメインが public suffix であるかを判断します。使用しているプロトコル (http/https) やポートが何であっても、ブラウザはサブドメインを含めて Cookie を使用可能にします。Cookie を設定するときに Domain、Path、Secure、Http-Only フラグを使用して、これらを制限できます。Cookie を読み取るとき、Cookie を設定した場所から知ることはできません。セキュアな https 接続のみ使用していたとしても、参照している Cookie がセキュアでない接続を使用して設定された可能性があります。
関連情報
Original Document Information
- Author(s): Jesse Ruderman