Cross-Origin Resource Sharing (CORS) 仕様

0 件のコメント

以前、クライアントサイドからリソースを利用するためにどうしたら良いか程度は、少し調べはしていたのですが、 今回は、サーバーサイドも含めて W3C の "Cross-Origin Resource Sharing" に記載されている内容を改めて読み直し & まとめておこうと思いました。 …が、結局、ほとんど仕様の日本語化になってしまいました。。 面倒で端折っている部分もありますが、ほぼ訳されています。

※ここに記載される内容は 2014年1月16日 の Cross-Origin Resource Sharing (Recommendation) 仕様になります。

目次

用語

単純なメソッド

  • GET
  • HEAD
  • POST

単純なヘッダー

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

※ Content-Type ヘッダー は、キーバリューの組み合わせで上記のものを満たす場合、単純なヘッダーとなります。

単純なレスポンスヘッダー

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

リクエスト / レスポンス ヘッダー

レスポンスヘッダー

Access-Control-Allow-Origin レスポンスヘッダー

アクセスが許可されているオリジンがどこかに関する情報を返します。 "*"、"null"、"URLリスト"のいずれかで返します。 Origin リクエストヘッダー に対応します。

Access-Control-Allow-Origin: *

Access-Control-Allow-Credentials レスポンスヘッダー

プリフライトリクエストに対するレスポンスの1つ。 CORSを行う際、Cookie も共有する場合、true を返します。Cookie を共有しない場合は false を返します。 true を返す際は、 Access-Control-Allow-Origin に "*" が指定できません。 必ず Access-Control-Allow-Origin に CORS を行う オリジン を指定します。 指定する オリジン は リクエスト で受け取る Originヘッダー の値をそのまま使います。 大文字小文字を区別する "true" または "false" のいずれかを返します。

Access-Control-Allow-Origin: http://sample.co.jp/
Access-Control-Allow-Credentials: true

Access-Control-Expose-Headers レスポンスヘッダー

利用可能なレスポンスヘッダーのホワイトリストを返します。 サーバーからクライアントへレスポンスを返す際、クライアント側で利用可能なカスタムヘッダーのリストになります。

Access-Control-Expose-Headers: X-Custom-Response-Header
X-Custom-Response-Header: foobar

Access-Control-Max-Age レスポンスヘッダー

プリフライトリクエストに対するレスポンスの1つ。 プリフライトリクエストをキャッシュする時間を秒で指定します。

Access-Control-Max-Age: 86400

Access-Control-Allow-Methods レスポンスヘッダー

プリフライトリクエストに対するレスポンスの1つ。 クライアントからサーバーへリクエストする際、サーバー側で受付可能なメソッドのリストを返します。 クライアントから来る Access-Control-Request-Method リクエストヘッダー に対応します。

Access-Control-Allow-Methods: POST, GET, OPTIONS

Access-Control-Allow-Headers レスポンスヘッダー

プリフライトリクエストに対するレスポンスの1つ。 クライアントからサーバーへリクエストする際、サーバー側で受付可能なヘッダーのリストを返します。 クライアントから来る Access-Control-Request-Headers リクエストヘッダー に対応します。

Access-Control-Allow-Headers: X-Custom-Request-Header

リクエストヘッダー

主にブラウザが実装するもの。 新しいブラウザなら対応しているはず どれくらい新しいブラウザが対応しているかは…不明。

Origin リクエストヘッダー

プリフライトリクエストとしてサーバーにリクエストされるヘッダーです。 異なるサーバーへ Ajax アクセス する場合、ブラウザが自動的にプリフライトリクエストとして送信します。

Origin: http://sample.co.jp/

Access-Control-Request-Method リクエストヘッダー

プリフライトリクエストとしてサーバーにリクエストされるヘッダーです。 サーバー側に利用したいメソッドを通知します。 サーバー側からは Access-Control-Allow-Methods レスポンスヘッダー に許可されたメソッドのリストが記載されて返ってきます。

Access-Control-Request-Method: POST

Access-Control-Request-Headers リクエストヘッダー

プリフライトリクエストとしてサーバーにリクエストされるヘッダーです。 サーバー側に利用したいヘッダーを通知します。 サーバー側からは Access-Control-Allow-Headers レスポンスヘッダー に許可されたヘッダーのリストが記載されて返ってきます。

Access-Control-Request-Headers: X-Custom-Request-Header

リソースサーバー 処理

リソース提供側のプロセスモデルについて記載します。 ここで記載されるプロセスは、リソースを提供するサーバーサイドの処理フローになります。

サーバーサイドで使われる設定に以下のものがあります。

リソース サーバー 設定

list of origins
リソースサーバーにアクセス可能(リソース共有可能)な Origin のリスト
list of methods
リソースサーバーがサポートするメソッドリスト
list of headers
リソースサーバーがサポートするヘッダーリスト
list of exposed headers
リソースサーバーがクライアントサイドに利用を許可するヘッダーリスト
supports credentials
認証情報をサポートするかどうか

シンプル リクエスト

  1. Originヘッダー がなければ終了
  2. Originヘッダー の値がリソース共有するドメインのリストと一致しなかった場合、何もせず終了 ※ドメイン名は大文字小文字を区別する
  3. 認証情報サポート [supports credentials] が true の場合
    Access-Control-Allow-Origine: [Orignヘッダーに記載の値]
    Access-Control-Allow-Credentials: true
    
    認証情報サポート [supports credentials] が false の場合
    Access-Control-Allow-Origin: ["*" または Originヘッダーに記載の値]
    
  4. Exposed Header List を Access-Control-Expose-Headers で出力

プリフライト リクエスト

  1. Originヘッダー がなければ終了
  2. Originヘッダー の値がリソース共有するドメインのリスト[list of origins] と一致しなかった場合、何もせず終了 ※ドメイン名は大文字小文字を区別しない
  3. Access-Control-Request-Method ヘッダー をパース。 Access-Control-Request-Method ヘッダー が存在しない、値のパースに失敗、値が存在しない場合、何もせず終了
  4. リクエストメソッドが、サポートするメソッドリスト [list of methods] のいずれとも一致しない場合、何もせず終了 ※メソッド名は大文字小文字を区別しない
  5. Access-Control-Request-Method ヘッダー の値が、サポートするメソッドリスト[list of methods] のいずれとも一致しない場合、何もせず終了 ※メソッド名は大文字小文字を区別しない
  6. 認証情報サポート [supports credentials] が true の場合、 Access-Control-Allow-Origin ヘッダー および Access-Control-Allow-Credentials ヘッダー を レスポンスヘッダー に追加
    Access-Control-Allow-Origine: [Orignヘッダーに記載の値]
    Access-Control-Allow-Credentials: true
    
    認証情報サポート [supports credentials] が false の場合、 Access-Control-Allow-Origin ヘッダー を レスポンスヘッダー に追加
    Access-Control-Allow-Origin: ["*" または Originヘッダーに記載の値]
    
  7. 任意で、レスポンスに Access-Control-Max-Age ヘッダー を追加
    Access-Control-Max-Age: [キャッシュする時間(秒)]
    
  8. リクエストメソッド が 単純なメソッド でない場合、 サポートするメソッドリスト [list of methods] の一部を含む Access-Control-Allow-Methods ヘッダー を レスポンスヘッダー に追加 ※ サポートするメソッドリスト [list of methods] に設定がない場合、Access-Control-Request-Method の値を、許可できる場合は、そのまま使ってもよい
    Access-Control-Allow-Methods: [許可するメソッドリスト]
    
  9. Access-Control-Request-Method ヘッダー の値が、単純なヘッダーでない または Content-Type である場合、 Access-Control-Allow-Headers ヘッダー を 1つ以上 レスポンスヘッダー に追加
    Access-Control-Allow-Headers: [許可するヘッダーリスト]
    

クライアント 処理

ここで記載されるプロセスは、クライアント側(ブラウザ)の処理フローになります。 ブラウザ処理なので、通常の Webアプリ開発 においては、まず実装することがないと思います。

クライアントサイド(ブラウザ)で使われる設定に以下のものがあります。

クライアント 設定

request URL
リソースへのリクエストURL。
request method
リクエストメソッド。明示的に設定されなければ、GETを設定。
reques headers
リクエストヘッダー。明示的に設定されなければ、空を設定。
request body
リクエスト本文。
source orgin
リクエストの生成元ドメイン名
referrer source
Refererヘッダーに定義される document または URL。
redirect flag
自動的にリダイレクトするかどうか。
omit credentials flag
認証情報を無視するかどうか。
preflight flag
プリフライトリクエストが必要かどうか。

シンプル リクエスト

  1. ソースサーバードメイン名 を Origin ヘッダー に追加して、リソースサーバー へ リクエスト

プリフライト リクエスト

  1. 以下の条件を満たす場合、次のステップへ 上記条件を満たさない場合、プリフライト リクエスト
    1. リソースサーバーに 以下の条件 で リクエスト(プリフライトリクエスト)
      • POSTS メソッド
      • Access-Control-Request-Method ヘッダー を追加
      • リソースサーバー との間で カスタムヘッダー を利用する場合、Access-Control-Request-Headers ヘッダー を追加
      • カスタムヘッダー は 削除
      • Cookie は 送信しない
      • リクエストボディ は 空
    1. レスポンスからリソース共有が可能かどうかの判定を行い、共有できない場合、ネットワークエラーとする
    2. Access-Control-Allow-Methods ヘッダー があり、パースできない場合、ネットワークエラーとする
    3. Access-Control-Allow-Headers ヘッダー があり、パースできない場合、ネットワークエラーとする
    4. Access-Control-Allow-Methods ヘッダー に値がある場合、その値のいずれともリクエストメソッドが一致しない場合、ネットワークエラーとする
    5. Access-Control-Allow-Headers ヘッダー に値がある場合、その値のいずれか または 単純なヘッダー のどちらとも一致しない場合、ネットワークエラーとする
    6. Access-Control-Max-Age ヘッダー がある場合、プリフライト 結果 キャッシュ の max-age を設定する
    7. Access-Control-Allow-Methods の値ごとに プリフライト 結果 キャッシュ を作成
    8. Access-Control-Allow-Headers の値ごとに プリフライト 結果 キャッシュ を作成

リソース共有が可能かどうかの判定

  1. Access-Control-Allow-Origin ヘッダー の値が 0 または 1 より多い 場合 (= 1 以外の場合)、false を返却して終了
  2. Access-Control-Allow-Origin ヘッダー の値が "*" かつ Access-Control-Allow-Credentials ヘッダー の値が "true" 以外の場合、true を返却して終了
  3. Access-Control-Allow-Origin ヘッダー の値が Origin ヘッダー に指定した値 と大文字小文字を区別して一致しない場合、 false を返して終了
  4. Access-Control-Allow-Credentials ヘッダー の値が "true" かつ Access-Control-Allow-Credentials ヘッダーの値が 0 または 1 より多い場合 (= 1 以外の場合)、 false を返却して終了
  5. Access-Control-Allow-Credentials ヘッダー の値が "true" でない場合、 false を返して終了
  6. true を返却

プリフライト 結果 キャッシュ

プリフライトを行い、成功した場合、その結果をクライアント(ブラウザ)にキャッシュします。

origin
生成元ドメイン名
url
リクエストURL
max-age
Access-Control-Max-Age ヘッダーの値
credentials
認証情報を利用するかどうか(クッキーを利用するかどうか)
method
Access-Control-Allow-Methods ヘッダーの値
header
Access-Control-Allow-Headers ヘッダーの値

参考記事

最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!