Same Origin Policy(同一オリジンポリシー)とCORS(オリジン間リソース共有)


CORS(オリジン間リソース共有)についてふんわりとしか理解できていなかったので、調べた。

Originとは

まず初めにそもそもオリジンとは?

二つのページの プロトコルポート番号 (もしあれば)、 ホスト が等しい場合、両者のページは同じオリジンです。
https://store.company.com

  • store.company.com がドメイン
  • https://store.company.com:81 までがオリジン

同一オリジンポリシー(Same Origin Policy)

CORSに入る前に、まず、ブラウザは同一オリジンポリシーというものに従っている。

同一オリジンポリシーとは、あるオリジンから読み込まれた文書やスクリプトについて、そのリソースから他のオリジンのリソースにアクセスできないように制限するものです。

  • URLで指定してアクセスしているサーバーから取得した結果からさらに他のリソースへアクセスする
  • 同じオリジンのリソースにアクセスする場合は、Same-origin requests
  • 別のオリジンのリソースにアクセスする場合は、Cross-origin requests
  • Cross-origin requests ができないように制御する

目的

同一オリジンポリシーはウェブのセキュリティにおける重要な仕組みであり、悪意ある行動を起こしかねないリソースの分離を目的としています。

  • JavaScriptなどのクライアントスクリプトからサイトをまたがったアクセスを禁止するセキュリティ上の制限。
  • つまり、異なるオリジンのアプリケーションから勝手にアクセスされないようにする
  • 上記の図でいうと、domain-a.comは相手側(domain-b.com)の許可なしに、domain-b.comのリソースにアクセスすることができない。

同一オリジンポリシーの制限を受けるもの

  • XMLHttpRequest
  • Canvas
  • Web Storage
  • X-Frame-Options

同一オリジンポリシーの制限を受けないもの

  • frame要素とiframe要素
  • image要素
    • <img src=“xxxx”>
  • script要素
    • <script src=“xxx”><script>
  • css
  • formのaction属性

オリジン間リソース共有 (CORS)

同一オリジンポリシーでXMLHttpRequestについては相手側の許可があれば、同一オリジンでなくても通信ができるという規約がある。それがCORS。

  • シンプルなリクエストの場合は XMLHttpRequest を用いてHTTPリクエストを送ることが相手側の許可なしに可能
    • シンプルなリクエストについては後述。
  • シンプルなリクエストの条件を満たさない場合については、 OPTIONS リクエストメソッドを用いたプリフライトリクエストを送信して、サーバーからの認可が降りたら、実際のリクエストを送信できる

シンプルなリクエスト

プリフライトリクエスト

  • ブラウザはJavaScript コードで使用しているリクエストの引数に基づいて、プリフライトの送信が必要であることを判断する。
  • プリフライトリクエスト(一部) Origin: http://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
  • Access-Control-Request-Method ヘッダー

    実際のリクエストが行われた際にどの HTTP メソッドが使用されるかをサーバーに知らせるために使用されます。プリフライトリクエストは常に OPTIONS であり、実際のリクエストとは同じメソッドを使用しないため、このヘッダーが必要です。

  • Access-Control-Request-Headers ヘッダー

    実際のリクエストが行う際にどの HTTP ヘッダー を使用するかをサーバーに知らせます。

  • プリフライトリクエストに対していのサーバーからのレスポンス(一部)

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

プリフライトリクエストを受け取ったAPIは、Access-Control-Request-MethodとAccess-Control-Request-Headersに対応する必要がある

  • Access-Control-Allow-Origin

    指定された オリジン からのリクエストを行うコードでレスポンスが共有できるかどうかを示します。

    • リクエストのOriginに対応
  • Access-Control-Request-Method

    リソースにアクセスするときに利用できる1つまたは複数のメソッドを指定します。

    • リクエストのAccess-Control-Request-Methodに対応
  • Access-Control-Allow-Headers

    実際のリクエストの間に使用できる HTTP ヘッダーを示すために使用されます。

    • リクエストのAccess-Control-Request-Headersに対応
  • Access-Control-Max-Ag

    プリフライトリクエストを再び送らなくてもいいように、プリフライトのレスポンスをキャッシュしてよい時間を秒数で与えます。この例では86400秒、つまり24時間です。

認証情報を含むリクエスト

  • デフォルトではクロスオリジンに対するリクエストにはHTTP認証やクッキーなどの認証に用いられるリクエストヘッダは返信されない
  • XMLHttpRequestのプロパティwithCredentialsをtrueにする必要がある。

  • かつ、サーバーからのレスポンスヘッダでは Access-Control-Allow-Credentials をtrueに設定する必要がある

  • Access-Control-Allow-Originはワイルドカードではなくオリジンを指定しなければならない

    サーバーは Access-Control-Allow-Origin ヘッダーで “” ワイルドカードではなくオリジンを指定しなければなりません*。

参考