Open3
【記事の草案】CORSの仕様を理解する
CORSを理解するための前提知識
オリジンとは?
ウェブコンテンツにアクセスするために使われる URL の スキーム (プロトコル)、 ホスト (ドメイン)、 ポート番号の組み合わせによって定義されるもののこと。
同一オリジンとは?
以下の条件を満たしているオリジンのこと。
- URLのホストが一致していること。
- スキーム(httpやhttpsといったプロトコル)が一致しているか?
- ポート番号が一致しているか?
同一オリジンポリシーとは?
- あるオリジンによって読み込まれた文書やスクリプト(JSなどのクライアントスクリプト)が、他のオリジンにあるリソースにアクセスできる方法を制限する、ブラウザのサンドボックスに用意された制限の一つのこと。
Access-Control-Allow-Originとは?
- クロスオリジンからの読み出しを許可するための仕掛けのことで、情報の提供元となるオリジンからHTTPレスポンスヘッダとして出力される。
- 例えば、
http://example.com
に対してアクセスを許可したい場合には、以下のHTTPレスポンスヘッダをクライアントに返す。Access-Control-Allow-Origin: http://example.com
CORS (オリジン間リソース共有、 Cross-Origin Resource Sharing)
概要
- XMLHttpRequestやFetch APIなどいくつかの局面において、同一オリジンポリシーによる制限を超えてサイト(オリジン)間でデータをやり取りをするための仕様として策定された。
いくつかのパターン
【リクエスト自体はできるが、レスポンスは利用できない場合】
以下の条件を満たす、シンプルなリクエストの場合は、異なるオリジンへのリクエスト自体はできてしまう。
しかし、レスポンスをブラウザでは利用できず、CORSヘッダー(Access-Control-Allow-Origin)が不足している旨で、ブラウザ上でエラーになる。
- HTTPメソッドは以下のいずれかであること。
- GET
- HEAD
- POST
- XMLHttpRequestオブジェクトのsetRequestHeaderメソッドで設定するリクエストヘッダは以下のものに限られていること。
- Accept
- Accept-Language
- Content-Language
- Content-Type
- 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
プリフライトリクエストする場合のフローは以下のようになる。
- フロントエンドから、オリジンが異なるAPIにGETリクエストを送信しようとする。
- 「シンプルなリクエスト」の条件を満たさないので、APIサーバーにGETリクエストする前に、ブラウザからAPIサーバーへ、OPTIONSメソッドを用いてプリフライトリクエストする。
- APIサーバーは、プリフライトリクエストのレスポンスを返す。
- ブラウザは、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
を付与する必要がある。- これがないと、ブラウザ側で同一オリジンポリシーによるエラーになる。
参考文献
残り
- 認証情報を含むリクエストを行う場合
- 同一オリジンポリシーがあっても、XSS攻撃を受けてしまう話。
- CSRFについて。