同一オリジンポリシーとCORSに再入門する

同一オリジンポリシーとCORSは、Web開発者であれば常識だと思うが、なんとなーくしか理解できていないので勉強がてらまとめてみた。

同一オリジンポリシー

同一オリジンポリシーとは

同一オリジンポリシー(same origin policy)とは、JavaScriptなどのクライアントスクリプトからサイトをまたがったアクセスを禁止するセキュリティ上の制限のこと。
Webブラウザサンドボックスに用意された制限の一つ。
受動的攻撃を防止するための対策。

同一オリジンである条件

同一オリジンと判定される条件は以下の通り。

  • URLのホスト(FQDN)が一致している
  • スキーム(プロトコル)が一致している
  • ポート番号が一致している

JavaScript以外のクロスドメインアクセス

JavaScript以外のブラウザ機能では、クロスドメインアクセスが許可されているものがある。

  • frame要素とiframe要素
  • img要素
  • script要素
  • CSS
    • CSSを呼び出せても問題ないはずだが、InternetExplorerにはCSSXSSと呼ばれる脆弱性が過去にあった。
  • form要素のaction属性
    • formの送信はJavaScriptから常に操作でき、この仕様を悪用した攻撃手法がCSRF攻撃。CSRF攻撃はユーザの意図しないformを送信させられる。

CORS

CORSとは

同一オリジンポリシーの制限を超えて、サイト間でデータやりとりしたいニーズに対応した仕様。
クロスオリジンでのデータアクセスを可能にしている。

シンプルなリクエス

下記のシンプルなリクエストの条件を満たしているリクエストの場合、XMLHttpRequestを用いて異なるオリジンにHTTPリクエストを送ることができる。

HTMLフォームから送られるリクエストを基準として、過度にリスクが増加しない範囲で条件が選択されている。

以下の条件をすべて満たすものを「シンプルなリクエスト」としている。

  • メソッドは下記のうちいずれか
    • GET
    • HEAD
    • POST
  • XMLHttpRequestオブジェクトのsetRequestHeaderメソッドで設定するリクエストヘッダは以下に限る
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
  • Content-Typeヘッダは以下のいずれかであること
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

originの許可

ClientからServerへクロスオリジンリクエストのシーケンス

alt

リクエス

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example

リクエストで送っているOriginで呼び出しが https://foo.example から来たことを示している。

レスポンス

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[…XML データ…]

レスポンスでは、サーバーがAccess-Control-Allow-Originヘッダーを返信している。
https://foo.example 以外のドメインはすべて、サイト間の方法でリソースにアクセスすることができなくなっている。 Access-Control-Allow-Origin ヘッダーに、リクエストの Origin ヘッダーの中で送信された値を含めることでリソースへのアクセスを許可できる。

プリフライトリクエス

クロスオリジンアクセスにおいて、「シンプルなリクエスト」の条件を満たさない場合、ブラウザはプリフライトリクエストというHTTPリクエストを送信する。
プリフライトリクエストは始めに OPTIONS メソッドによる HTTP リクエストを他のドメインにあるリソースに向けて送り、実際のリクエストを送信しても安全かどうかを確かめるリクエスト。

プリフライトリクエストのシーケンス alt

要求に対するリクエストとレスポンスの対応表

要求の種類 リクエス レスポンス
メソッドに対する許可 Access-Control-Request-Method Access-Control-Allow-Methods
ヘッダに対する許可 Access-Control-Request-Headers Access-Control-Allow-Headers
オリジンに対する許可 Origin Access-Control-Allow-Origin

認証情報を含むリクエス

XMLHttpRequestのプロパティ「withCredentials」で、クロスオリジンのajax通信で、リクエストにcookieなどの認証情報を含めるか否かを設定できます。デフォルトでは含まれない。
クロスオリジンで認証情報の送信を許可するためには、サーバー側で以下のようにヘッダーを返す必要がある。

Access-Control-Allow-Origin: https://syncer.jp
Access-Control-Allow-Credentials: true

参考