同一オリジンポリシーとは、あるオリジンから読み込まれた文書やスクリプトについて、そのリソースから他のオリジンのリソースにアクセスできないように制限するものです。同一オリジンポリシーは Web セキュリティにおける重要な仕組みであり、悪意ある行動を起こしかねないリソースの分離を目的としています。
オリジンの定義
2 つのページにおいてスキームと(与えられていれば)ポート、及びホストがそれぞれ等しい場合、両者のページは同一のオリジンを有していると見なします。以下の表は、各行の 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:
URL のコンテンツは、その URL を読み込んだドキュメントからオリジンを継承します。これは URL 自体にオリジンの情報がないためです。一方 data: URL は継承を行わず、空のセキュリティコンテキストを新しく作成します。
補足: Gecko 6.0 以前のアドレスバーに入力された data
URL は、その時点にブラウザが表示していたページのセキュリティコンテキストを継承していました。
IE における例外事項
Internet Explorer には、同一オリジンポリシーについて 2 つ大きな例外があります。
- 信頼済みゾーン: 双方のドメインが高く信頼されたゾーン(企業のドメインなど)である場合は、同一オリジンの制限が適用されません。
- ポート: IE は同一オリジンの確認要素にポートを含みません。従って、https://company.com:81/index.html と https://company.com/index.html は同一オリジンとみなされ、制限は適用されません。
これらの例外事項は非標準であり、 他のブラウザでこのような挙動はサポートされていません。しかし、Windows RT や IE ベースの Web アプリケーションを開発する場合は役に立つかもしれません。
オリジンの変更
ページのオリジンは、いくつかの制限の下で変更されることがあります。スクリプトを用いると、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
" に変更したと仮定します。詳しくは 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
に設定することが必要です。この作業は、単に親ドメインを元の値に戻す際にも必要です。これを怠るとパーミッションエラーが発生するでしょう。
異なるオリジンへのネットワークアクセス
XMLHttpRequest
や <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 の各項目を参照してください。<img>
による画像。サポートされる画像形式は PNG、JPEG、GIF、BMP、SVG などです。<video>
および<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
、window.parent
、window.open
、window.opener
といった JavaScript API を用いると、ドキュメントが直接互いに参照することができます。2 つのドキュメントが同一のオリジンではない場合、Window
オブジェクトや Location
オブジェクトなど、限られたオブジェクトにのみアクセスすることができます。詳しくは次の 2 つのセクションで説明します。
window.postMessage
を使用すると、異なるオリジンのドキュメント間における通信がさらに可能となります。
Window
仕様書: https://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#security-window
以下に示した Window
のプロパティは、異なるオリジンからのアクセスが許可されています。
メソッド |
---|
window.blur |
window.close |
window.focus |
window.postMessage |
属性 | |
---|---|
window.closed |
読み取りのみ |
window.frames |
読み取りのみ |
window.length |
読み取りのみ |
window.location |
読み取り/書き込み |
window.opener |
読み取りのみ |
window.parent |
読み取りのみ |
window.self |
読み取りのみ |
window.top |
読み取りのみ |
window.window |
読み取りのみ |
一部のブラウザでは、仕様書で定められたものより多くのプロパティでアクセスが許可されています。
Location
仕様書: https://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#security-location
以下に示した Location
のプロパティは、異なるオリジンからのアクセスが許可されています。
メソッド |
---|
location.replace |
属性 | |
---|---|
URLUtils.href |
書き込みのみ |
一部のブラウザでは、仕様書で定められたものより多くのプロパティでアクセスが許可されています。
オリジンをまたいだデータストレージアクセス
localStorage や IndexedDB など、ブラウザ内部に保存されるデータへのアクセスは、オリジンによって権限が分かれています。それぞれのオリジンが個別にストレージを持ち、あるオリジンの JavaScript から別のオリジンに属するストレージを読み書きすることはできません。
Cookie におけるオリジンの定義は異なります。ページは自身のドメインまたは任意の親ドメイン(親ドメインが public suffix ではない場合に限る)用の Cookie を設定できます。 ドメインが public suffix であるかを判断する際、Firefox と Chrome は Public Suffix List を使用します。Internet Explorer は独自の方法で public suffix であるかを判断します。使用しているスキーム (http/https) やポートに関係なく、ブラウザはサブドメインも含めて Cookie を使用可能にします。Cookie の設定時に Domain、Path、Secure、Http-Only フラグを用いることで、その Cookie の利用範囲を制限できます。Cookie を読み取るとき、Cookie を設定した場所から知ることはできません。安全な https 接続のみ使用していたとしても、参照している Cookie は安全でない接続を通じて設定された可能性があります。
関連情報
出典
- 著者: Jesse Ruderman