同一オリジンポリシー / CORS
同一オリジンポリシー(Same origin policy)と、その制限を回避する機能であるCORS(Cross-Origin Resource Sharing)について図を使って分かりやすくまとめてみました。
同一オリジンポリシーについてオリジンとは同一オリジンポリシーとは同一オリジンポリシーが必要な理由クロスサイトスクリプティング(XSS)攻撃を防ぐためクロスサイトリクエストフォージェリ(CSRF)攻撃を防ぐため情報漏洩を防ぐため同一オリジンポリシーの適用対象同一オリジンポリシーによって制限を受けるもの同一オリジンポリシーによって制限を受けないものCORSについて(同一オリジンポリシーの回避)CORSとは通信フローシンプルリクエストの場合の通信フロープリフライトリクエストの場合の通信フローCORSに関連するHTTPヘッダ一覧
同一オリジンポリシーについて
オリジンとは
まず、オリジン(Origin)とはそのまま直訳すると「出所」や「起源」という意味で、IT用語では「コンテンツ(情報)の送信元」のことを表すと思えば良いです。
具体的にはサーバのURL内の「スキーム(プロトコル)」+「FQDN(ホスト+ドメイン)」+「ポート番号」の部分を指します。
以下の図を例に説明すると、URL「https://www.aaa.com:443/blog/page」からコンテンツを取得する際、オリジンは「https://www.aaa.com:443」となります。
同一オリジンポリシーとは
同一オリジンポリシー(Same-Origin Policy: SOP)とは、あるオリジン(コンテンツ送信元)から取得したリソースから、別のオリジンのリソースへのアクセスを禁止するブラウザの機能のことです。
日本語では「同一生成元ポリシー」や「同一源泉ポリシー」とも表記されます。
具体例を示します。
オリジン「https://aaa.com」から取得したリソースaが、追加でリソースAとリソースBを取得する場面において、同一オリジンポリシーが適用された結果を下記の図で表しました。
- リソースAは、リソースaと同一のオリジン「https://aaa.com」なので、リソースの表示に成功します!
- リソースBは、リソースaと異なるオリジン「https://bbb.com」なので、リソースの表示に失敗します。
同一オリジンポリシーが必要な理由
クロスサイトスクリプティング(XSS)攻撃を防ぐため
同一オリジンポリシーがないと、攻撃者が悪意のあるスクリプトをウェブサイトに注入し、ユーザのブラウザで実行させるXSS攻撃が可能となります。
攻撃スクリプトは被害者のアクセスしている他のウェブサイトの情報を自由に盗み取ったり、操作したりできてしまいます。
クロスサイトリクエストフォージェリ(CSRF)攻撃を防ぐため
同一オリジンポリシーがないと、ユーザーがログインしているウェブサイトに対して、ユーザーに気づかれずに不正なリクエストを送信するCSRF攻撃が可能となります。
攻撃者はユーザの認証情報を悪用して、例えば勝手に商品の購入やパスワードの変更などを行えてしまいます。
情報漏洩を防ぐため
ログイン後のみ表示される情報等を他のサイトから参照されることを防ぐために同一オリジンポリシーが必要です。
同一オリジンポリシーの適用対象
同一オリジンポリシーが適用される対象(読み込みなどで制限受ける対象)および、適用されない対象(制限を受けない対象)についてまとめてみた。
同一オリジンポリシーによって制限を受けるもの
異なるオリジンからのリソースの読み込みは一般的に禁止される。(同一オリジンポリシーの適用対象)
- JavaScriptでの非同期通信(XMLHttpRequestやFetch APIを使った通信)
- Canvas
- Web Storage
- JavaScriptでの画像データの読み込み
同一オリジンポリシーによって制限を受けないもの
異なるオリジンへのアクセス・書き込みや、異なるオリジンのリソースの埋め込みは許可される。(同一オリジンポリシーの適用対象外)
- タグ内の属性で読み込まれるJavaScript
- タグ内の属性で読み込まれるCSS
- タグ内の属性で埋め込まれる画像
- , タグ内の属性で埋め込まれるメディアファイル
- , で指定されたリソース
- , , タグによるプラグイン
- , タグ内の属性での別サイトコンテンツの読み込み
- タグ内の属性で指定した情報送信先
CORSについて(同一オリジンポリシーの回避)
CORSとは
CORS(Cross-Origin Resource Sharing)とは、同一オリジンポリシーの制限を回避する際に利用する機能です。
外部APIを使いたい場合などに、異なるオリジンのサーバからのアクセスを許可できる仕組みとなります。
異なるオリジンからのリソースを読み込もうとした場合、ブラウザは以下のようなエラーをコンソールに出力し、読み込みを禁止します。
異なるオリジンのサーバからのアクセスを許可したい場合、レスポンス内の「Access-Control-Allow-Origin」と呼ばれるHTTPヘッダの値に、許可したいサーバのオリジン情報を設定しておくことで正常なアクセスが可能となります。
通信フロー
CORSによって異なるオリジンからのリソースの読み込みを許可する場合の通信フローを示す。
HTTPリクエストの種別( or )によって通信フローは異なる。
シンプルリクエストとは
通信によりサーバのデータが変化しないHTTPリクエスト。
具体的には下記の条件を満たすHTTPリクエスト。
- メソッドが or or
- HTTPヘッダが下記以外のものは含まない
, , , , , , , ,
- Content-Typeが or or
プリフライトリクエストとは
シンプルリクエストの条件を満たさず、通信によりサーバのデータが変化する恐れのあるHTTPリクエスト。
実際のリクエストの前にメソッドによって通信し、実際のリクエストを送っても問題ないかを確認する工程がある。
シンプルリクエストの場合の通信フロー
① クライアントは https://aaa.com へアクセス。
② サーバ aaa.com はレスポンスを返す。
③ ブラウザは追加コンテンツを取得するため、https://bbb.com へアクセス。
Originヘッダにて、呼び出し元のオリジン(https://aaa.com/)を指定する。
④ サーバ bbb.com はAccess-Control-Allow-Originヘッダに表示を許可する呼び出し元として https://aaa.com/ を指定し、コンテンツを送信。
プリフライトリクエストの場合の通信フロー
異なるオリジンへの通信の際、始めに OPTIONS メソッドで対象の異なるオリジンにリクエストを送り、実際のリクエストを送っても問題ないかを確認する。
① クライアントは https://aaa.com へアクセス。
② aaa.com のサーバはレスポンスを返す。
③ ブラウザは https://bbb.com へリクエスト送信して問題ないかを確認。(呼び出し元ドメインや送信予定のリクエストのメソッド・ヘッダ情報を送信)
④ サーバ bbb.com は③の条件のリクエストを受け入れOKの場合、受け入れ可能条件を送信。
⑤ ブラウザは追加コンテンツ取得のため、https://bbb.com へアクセス。
⑥ サーバ bbb.com はAccess-Control-Allow-Originヘッダに表示を許可する呼び出し元として https://aaa.com/ を指定し、コンテンツを送信。