Open3

【記事の草案】CORSの仕様を理解する

おっちー(O.S)おっちー(O.S)

CORSを理解するための前提知識

オリジンとは?

ウェブコンテンツにアクセスするために使われる URL の スキーム (プロトコル)、 ホスト (ドメイン)、 ポート番号の組み合わせによって定義されるもののこと。

同一オリジンとは?

以下の条件を満たしているオリジンのこと。

  • URLのホストが一致していること。
  • スキーム(httpやhttpsといったプロトコル)が一致しているか?
  • ポート番号が一致しているか?

https://developer.mozilla.org/ja/docs/Glossary/Origin

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

  • あるオリジンによって読み込まれた文書やスクリプト(JSなどのクライアントスクリプト)が、他のオリジンにあるリソースにアクセスできる方法を制限する、ブラウザのサンドボックスに用意された制限の一つのこと。

https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy

Access-Control-Allow-Originとは?

  • クロスオリジンからの読み出しを許可するための仕掛けのことで、情報の提供元となるオリジンからHTTPレスポンスヘッダとして出力される。
  • 例えば、http://example.comに対してアクセスを許可したい場合には、以下のHTTPレスポンスヘッダをクライアントに返す。
    Access-Control-Allow-Origin: http://example.com
    
おっちー(O.S)おっちー(O.S)

CORS (オリジン間リソース共有、 Cross-Origin Resource Sharing)

概要

  • XMLHttpRequestやFetch APIなどいくつかの局面において、同一オリジンポリシーによる制限を超えてサイト(オリジン)間でデータをやり取りをするための仕様として策定された。

いくつかのパターン

【リクエスト自体はできるが、レスポンスは利用できない場合】

以下の条件を満たす、シンプルなリクエストの場合は、異なるオリジンへのリクエスト自体はできてしまう。
しかし、レスポンスをブラウザでは利用できず、CORSヘッダー(Access-Control-Allow-Origin)が不足している旨で、ブラウザ上でエラーになる。

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

【プリフライトリクエストする場合】

先ほどの「シンプルなリクエスト」の条件を満たさない場合は、ブラウザは、プリフライトリクエストというHTTPリクエストをする。
プリフライトリクエスト時には、以下のようなリクエストを送ることになっている。

OPTIONS /users HTTP/1.1
Host: api.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
Origin: http://example.com

また、それぞれ以下のような要求をしている。

要求内容 リクエスト レスポンス
メソッドに対する要求 Access-Control-Request-Method Access-Control-Allow-Methods
ヘッダに対する要求 Access-Control-Request-Headers Access-Control-Allow-Headers
オリジンに対する要求 Origin Access-Control-Allow-Origin

サーバーは、プリフライトリクエストに対して以下のようなレスポンスを返す。

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400

プリフライトリクエストする場合のフローは以下のようになる。

  1. フロントエンドから、オリジンが異なるAPIにGETリクエストを送信しようとする。
  2. 「シンプルなリクエスト」の条件を満たさないので、APIサーバーにGETリクエストする前に、ブラウザからAPIサーバーへ、OPTIONSメソッドを用いてプリフライトリクエストする。
  3. APIサーバーは、プリフライトリクエストのレスポンスを返す。
  4. ブラウザは、Access-Control-Allow-Origin ヘッダーが付与されたレスポンスであることを確認し、オリジンが異なるAPIにGETリクエストを送信する。

【認証情報を含むリクエストを行う場合】

クロスオリジンに対するリクエストにはHTTP認証やクッキーなどの認証に用いられるリクエストヘッダは自動的には送信されないため、以下の対応をする必要がある。

  • それを許可するオプションをJS側で付与する必要がある。(これにより、Cookieヘッダ等が付与されるようになる。)
    GET /protected-resource HTTP/1.1
    Host: api.example.com
    Origin: http://example.com
    Cookie: sessionid=your-session-id; other-cookie=value
    
  • APIサーバー側では、レスポンスを返す際に、レスポンスヘッダとしてAccess-Control-Allow-Credentials: trueを付与する必要がある。
    • これがないと、ブラウザ側で同一オリジンポリシーによるエラーになる。

参考文献

https://developer.mozilla.org/ja/docs/Glossary/CORS

おっちー(O.S)おっちー(O.S)

残り

  • 認証情報を含むリクエストを行う場合
  • 同一オリジンポリシーがあっても、XSS攻撃を受けてしまう話。
  • CSRFについて。