#はじめに

「CORSエラーでAPIが呼べない」——Web開発でよく遭遇するこのエラー、なぜ発生するのでしょうか?

その答えは「同一オリジンポリシー」にあります。このセキュリティ機能は、悪意のあるWebサイトからあなたの情報を守るために存在します。

この記事を読むと、以下のことができるようになります:

  • オリジンの定義を正確に理解できる
  • 同一オリジンポリシーがなぜ必要かがわかる
  • どのような操作が制限されるのかがわかる

#オリジンとは

オリジン(Origin)とは、URLの「スキーム + ホスト + ポート」の組み合わせです。

https://www.example.com:443/path/page.html
^^^^^   ^^^^^^^^^^^^^^^  ^^^
スキーム    ホスト       ポート

オリジン = https://www.example.com:443

#オリジンの比較例

URL AURL B同一オリジン?理由
https://example.comhttps://example.com/other✅ Yesパスは含まれない
https://example.comhttps://www.example.com❌ Noホストが異なる
https://example.comhttp://example.com❌ Noスキームが異なる
https://example.comhttps://example.com:8080❌ Noポートが異なる
https://example.com:443https://example.com✅ Yes443は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:blankjavascript: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タブでの確認

  1. DevToolsのNetworkタブを開く
  2. リクエストを確認
  3. ブロックされたリクエストは赤く表示されることがある
  4. Headersタブで詳細を確認

#まとめ

  • オリジン = スキーム + ホスト + ポート
  • 同一オリジンポリシーは、別オリジンのリソースへのアクセスを制限
  • レスポンスの読み取りを制限(リクエストは送信される)
  • ブラウザが実装しているセキュリティ機能
  • 悪意のあるサイトからユーザーの情報を保護するために必要

#次のステップ

同一オリジンポリシーの基本がわかったところで、次はCORSについて学びましょう。「別オリジンのAPIを呼び出したいときはどうすればいいのか」——CORSは、同一オリジンポリシーを安全に緩和するための仕組みです。

#参考リンク