#はじめに
「CORSエラーでAPIが呼べない」——Web開発でよく遭遇するこのエラー、なぜ発生するのでしょうか?
その答えは「同一オリジンポリシー」にあります。このセキュリティ機能は、悪意のあるWebサイトからあなたの情報を守るために存在します。
この記事を読むと、以下のことができるようになります:
- オリジンの定義を正確に理解できる
- 同一オリジンポリシーがなぜ必要かがわかる
- どのような操作が制限されるのかがわかる
#オリジンとは
オリジン(Origin)とは、URLの「スキーム + ホスト + ポート」の組み合わせです。
https://www.example.com:443/path/page.html
^^^^^ ^^^^^^^^^^^^^^^ ^^^
スキーム ホスト ポート
オリジン = https://www.example.com:443
#オリジンの比較例
| URL A | URL B | 同一オリジン? | 理由 |
|---|---|---|---|
https://example.com | https://example.com/other | ✅ Yes | パスは含まれない |
https://example.com | https://www.example.com | ❌ No | ホストが異なる |
https://example.com | http://example.com | ❌ No | スキームが異なる |
https://example.com | https://example.com:8080 | ❌ No | ポートが異なる |
https://example.com:443 | https://example.com | ✅ Yes | 443はHTTPSのデフォルト |
#ポートの省略
HTTPのデフォルトポートは80、HTTPSは443です。これらは省略可能で、明示しても同一オリジンとみなされます。
https://example.com = https://example.com:443
http://example.com = http://example.com:80
#同一オリジンポリシーとは
同一オリジンポリシー(Same-Origin Policy、SOP)とは、あるオリジンから読み込まれたスクリプトが、別のオリジンのリソースにアクセスすることを制限するセキュリティ機構です。
ブラウザに組み込まれた基本的なセキュリティ機能であり、デフォルトで有効になっています。
#なぜ必要なのか
同一オリジンポリシーがないと、どのような問題が起きるでしょうか?
#シナリオ: 悪意のあるサイトによるデータ窃取
1. あなたがbank.comにログイン中
2. 悪意のあるサイト evil.com を訪問
3. evil.com のJavaScriptが bank.com にリクエスト:
fetch('https://bank.com/api/account')
4. もし制限がなければ...
→ bank.com のCookieが送信される
→ 口座情報が evil.com に取得される
→ あなたの情報が盗まれる!
同一オリジンポリシーがあるため、evil.com のスクリプトは bank.com のレスポンスを読み取れません。
#保護されるもの
同一オリジンポリシーは以下を保護します:
- 機密データ: ログイン状態で取得できる情報
- ユーザーのセッション: Cookieなどの認証情報
- プライベートなリソース: 社内システムのデータなど
#何が制限されるのか
同一オリジンポリシーは、すべての通信をブロックするわけではありません。レスポンスの読み取りを制限します。
#制限される操作
| 操作 | 制限 |
|---|---|
fetch() / XMLHttpRequest | レスポンスの読み取りが制限 |
| iframe内のDOMアクセス | 別オリジンのiframe内にアクセス不可 |
| Canvas画像データの取得 | 別オリジンの画像をCanvasに描画後、データ取得不可 |
#許可される操作
| 操作 | 説明 |
|---|---|
<img>タグでの画像読み込み | 表示は可能(データ取得は不可) |
<script>タグでのスクリプト読み込み | 実行は可能 |
<link>タグでのCSS読み込み | 適用は可能 |
<form>タグでの送信 | 送信は可能(レスポンスは読めない) |
#重要な区別
「リクエストを送る」ことと「レスポンスを読む」ことは別です。
[evil.com] [bank.com]
| |
|------ fetch('bank.com/api') ------>| ← リクエストは送信される
| |
|<----- {balance: 1000000} ----------| ← レスポンスは返ってくる
| |
| ブラウザ: 「別オリジンなので読み取り禁止!」
|
| JavaScript: レスポンスにアクセスできない
リクエスト自体は送信されますが、JavaScriptはレスポンスを読み取れません。
#制限の具体例
#fetch / XMLHttpRequest
// example.com のページで実行
fetch('https://api.other.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
// エラー:
// Access to fetch at 'https://api.other.com/data' from origin
// 'https://example.com' has been blocked by CORS policy
#iframe
<!-- example.com のページ -->
<iframe id="frame" src="https://other.com/page"></iframe>
<script>
const frame = document.getElementById('frame');
// 別オリジンのiframe内にはアクセスできない
console.log(frame.contentDocument); // null または SecurityError
</script>
#Canvas
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = 'https://other.com/image.png';
img.onload = () => {
ctx.drawImage(img, 0, 0); // 描画は可能
// しかし、ピクセルデータの取得は制限される
ctx.getImageData(0, 0, 100, 100); // SecurityError
};
</script>
#オリジンの継承
特殊なケースでのオリジンについて理解しましょう。
#about と javascript:
about:blankやjavascript:URLで開かれたページは、開いたページのオリジンを継承します。
// example.com で実行
const win = window.open('about:blank');
// win のオリジンは example.com
#data: URL
data:URLはユニークなオリジンを持ち、どのオリジンとも同一ではありません。
<iframe src="data:text/html,<h1>Hello</h1>"></iframe>
<!-- このiframeは opaque origin(不透明オリジン)を持つ -->
#file: URL
file:URLのオリジンの扱いはブラウザによって異なります。多くのブラウザでは、セキュリティのために制限的に扱われます。
#DevToolsでの確認
#コンソールでのエラー確認
同一オリジンポリシー違反が発生すると、Consoleにエラーが表示されます。
Access to fetch at 'https://api.other.com/data' from origin
'https://example.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
#Networkタブでの確認
- DevToolsのNetworkタブを開く
- リクエストを確認
- ブロックされたリクエストは赤く表示されることがある
- Headersタブで詳細を確認
#まとめ
- オリジン = スキーム + ホスト + ポート
- 同一オリジンポリシーは、別オリジンのリソースへのアクセスを制限
- レスポンスの読み取りを制限(リクエストは送信される)
- ブラウザが実装しているセキュリティ機能
- 悪意のあるサイトからユーザーの情報を保護するために必要
#次のステップ
同一オリジンポリシーの基本がわかったところで、次はCORSについて学びましょう。「別オリジンのAPIを呼び出したいときはどうすればいいのか」——CORSは、同一オリジンポリシーを安全に緩和するための仕組みです。