クロスサイトリクエストフォージェリ(CSRF) などのセキュリティ攻撃を防止するために、ブラウザは「同一生成元ポリシー(Same-Origin Policy)」という仕組みを実装しています。「同一オリジンポリシー」とも訳されます。異なるオリジンのリソースへのアクセスに制約をかけるものです。制約はまた、JSONP や CORS(Cross-Origin Resource Sharing) と呼ばれる仕組みを利用することで一部解除することができます。
オリジン(Origin)は、スキーム、ホスト、ポート番号の組み合わせです。下記は同じオリジンとみなされます。
http://site-a.example.com/ http://site-a.example.com:80/ http://site-a.example.com/example.html
下記は異なるオリジンとみなされます。
https://site-a.example.com/ ← スキームが異なる http://site-b.example.com/ ← ホストが異なる http://site-a.example.com:8080/ ← ポート番号が異なる
ただし、Internet Explorer では、ポート番号のみが異なる場合は同じオリジンとみなします。
異なるオリジン(例えば site-a.example.com から site-b.example.com) に対する XMLHttpRequest や Fetch API を発行しても、その結果を responseText で読み出すことができません。呼び出せないのではなく、呼び出せてもその結果を取得できないことに注意してください。
<script> window.addEventListener('load', function() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { console.log("status = " + xhr.status); // status = 0 console.log(xhr.responseText); // Can not access } } xhr.open("POST", "http://site-b.example.com/"); xhr.setRequestHeader("Content-Type" , "application/x-www-form-urlencoded"); xhr.send("a=b&c=d"); }); </script>
この制約が発生すると、ブラウザのコンソールに下記の様なエラーメッセージが表示されます。
site-b 側で Access-Control-Allow-Origin ヘッダを返却することにより、この制約を解除することができます。
異なるオリジン(例えば site-a.example.com から site-b.example.com) の画像を Canvas に描画すると、Canvas は汚染された(tainted)とみなされ、canvas に対する toBlob(), toDataURL(), getImageData() などのアクセスが制限されます。
<script> window.addEventListener('load', function() { var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); var img = new Image(); img.src = "http://site-b.example.com/img/test.png" + "?" + new Date().getTime(); img.onload = function() { context.drawImage(img, 40, 40); var base64 = canvas.toDataURL("image/png"); // Error console.log(base64); } }); </script> <canvas id="canvas" width=100 height=100 style="border:1px solid gray;"></canvas>
この制約が発生すると、ブラウザのコンソールに下記の様なエラーメッセージが表示されます。
site-b 側で Access-Control-Allow-Origin ヘッダを返却し、イメージに crossorigin を設定することにより、この制約を解除することができます。
var img = new Image(); img.crossOrigin = "anonymous"; img.src = "http://site-b.example.com/img/test.png" + "?" + new Date().getTime();
異なるオリジン(例えば site-a.example.com から site-b.example.com) のコンテンツを iframe に表示した場合、そのフレームに対する contentWindow アクセスが制限されます。
<script> window.addEventListener('load', function() { var iframe = document.getElementById("iframe"); var doc = iframe.contentWindow.document; // Error console.log(doc); }); </script> <iframe src="http://site-b.example.com/" id="iframe"<>/iframe>
この制約が発生すると、ブラウザのコンソールに下記の様なエラーメッセージが表示されます。
この制約は解除することができないようです。
上記の他にも @font-face による外部フォントアクセス、WebGL によるアクセス、スクリプトに対する onerror による詳細エラー情報取得などに制約があるようです。制約の条件や範囲はブラウザの実装により異なります。
通常は異なるオリジン間でAPIなどを呼び出すことはできませんが、下記の対策を行うことにより対応することができます。