CORSの理解が不足していたのでメモ

CORSって何?

CORS: Cross-Origin Resource Sharing

オリジン間リソース共有

オリジンって何?

同じところからのリクエストであるかを判別するための方法

URIの、scheme、host、portが一致していると、それは「同一オリジン」である

scheme、host、portとか、URIの呼称については、こちらを参照

kasei-san.hatenadiary.org

どういう時に使うの?

異なるオリジンにAjaxリクエストやWebフォントの読み込みを行う際に使われる

なんで必要なの?

悪意あるサイトがAjaxで勝手にどこかAPIを叩けないよう、同一オリジン以外へのリクエストはブロックされるようになっている

  • これを、Same Origin Policy(同一オリジンポリシー) と呼ぶ

ただし、異なるオリジンにリクエストを投げる必要もあるため、CORS という仕組みが生まれた

どういう風にやるの?

単純リクエストという方式の場合、以下のような流れ

  1. ブラウザ側からリクエスト。リクエストヘッダの中に Origin が含まれる
    • Origin は、リクエストの発生元がどこであるかを示す
  2. サーバ側からレスポンス。レスポンスヘッダの中に Access-Control-Allow-Origin が含まれる
    • Access-Control-Allow-Origin はサーバが許可するオリジンを入れる
    • * の場合は「すべて許可」となるが、非常に脆弱なのでやめるべき
    • 複数の値を含めることはできない。許可すべきオリジンが複数ある場合は、サーバ側で制御する
  3. ブラウザ側で OriginAccess-Control-Allow-Origin が一致していれば、処理が行われる

プリフライトリクエスト

クロスオリジンのリクエストが いろいろな条件を満たさなかった場合、上記の単純リクエストではなく、プリフライトリクエストが行われる

ユーザーデータに影響を与える可能性があるようなリクエストの場合、プリフライトが行われる(らしい)

プリフライトリクエストの流れ

OPTIONS メソッドをつかって、事前に安全にクロスオリジンの通信が行えるかチェックする

以下のような流れ

  1. ブラウザ側で、 OPTIONS メソッドで以下のリクエストを投げる
    • Origin : 単純リクエストと同じ
    • Access-Control-Request-Method : 送るメソッド
    • Access-Control-Request-Headers : 送るリクエストヘッダ
  2. サーバ側からレスポンスを投げる。その時、以下のレスポンスヘッダを含む
    • Access-Control-Allow-Origin : 単純リクエストと同じ
    • Access-Control-Allow-Methods : 許可するメソッド
    • Access-Control-Allow-Headers : 許可するリクエストヘッダ
    • Access-Control-Max-Age: プリフライトリクエストの結果をキャッシュして良い時間(秒)
  3. ブラウザ側でレスポンスヘッダを読み込んで、問題なさそうならば実際のリクエストを開始する

資格情報を含むリクエスト

標準では cookie や basic 認証を含むリクエストに関わる情報は送信されない

そのためには、JavaScript 側で withCredentials というオプションを true にする必要がある

さらに、cookie の情報をやり取りしたい場合は、レスポンスヘッダに Access-Control-Allow-Credentials: true をつけて、許可する必要がある

また、Set-Cookie については、サードパーティCookieと同じく、ドメインが異なるとブラウザの設定によっては読み込めない

あと、 資格情報を含むリクエストの場合 Access-Control-Allow-Origin* は使えない

参考

yamory.io

developer.mozilla.org