🦍

blocked by CORS policyはもう怖くない!!コピペ解決はやめよう!!

2022/07/28に公開

CORSとは

オリジン間リソース共有(Cross-Origin Resource Sharing) 略してCORSです。
ざっくりいうと、
「オリジンをまたいだリソースへのアクセスを許可することができる仕組み」
がCORSです。オリジンが異なってもアクセスしてもいいよ〜ってことができるようですね。
余談ですがoriginとは下記の画像のことです。

blocked by CORS policyはなぜ発生するのか

そもそもwebはことなるオリジンのデータのやり取りを許可していません。これがデフォルトです。
開発者にとっては不便に思うかもしれないですが、セキュリティの観点からこれは必要です。悪意のある人が、知識のない人の銀行アカウントにアクセスし、送金を誘導するなんてことも容易にできてしまうわけですね。

言うなれば、ユーザーを守る仕組みです。

ブラウザがやっていること

CORSの仕組みに則ったブラウザが裏でやっていることは以下です。

  • (単純リクエストを除いて)プリフライトリクエストを送信する
  • レスポンスのHTTPヘッダーをチェックする

プリフライトリクエストとは

リクエストを送信する前にそのリクエストが安全そのリクエストが安全かどうかOPTIONSリクエストを送信して確かめる仕様です。ブラウザで危ないリクエストは弾いてしまおうということですね。

実際のリクエストの中身は以下の画像です。

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests

1回目リクエストを送信した後のレスポンスの中身を見てみましょう。

200OK
Access-Control-Allow-Origin:
Access-Control-Allow-Method
Access-Control-Allow-Headers

少々省きましたが、上のようなレスポンスが返ってきます。

  • アクセスを許可されているオリジンから送られるか?
  • 許可されているHTTPメソッドか?
  • 許可されているHTTPヘッダーだけを利用しているか?
    を確認し、もしOKならばメインリクエストの送信を実行します。

プリフライトリクエストが実行されない場合

「単純リクエスト(simple request)」とその他のリクエストに分けられていて、単純リクエストの場合はアクセストークンなどのセンシティブな情報が含まれている可能性が低いと判断されるため、OPTIONSは送信されません。

単純リクエストの要件

「単純リクエスト」は以下のすべての条件を満たすものになります。

  1. GET, HEAD, POSTのうちいずれか
  2. ヘッダーに含まれるのが以下のうちいずれか
  • ユーザーエージェントによって自動的に設定されたヘッダー
  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type
  1. Content-Typeのヘッダーが以下のうちいずれか
  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain
  1. リクエストに使用されるどの XMLHttpRequestUpload にもイベントリスナーが登録されていないこと。
  2. リクエストに ReadableStream オブジェクトが使用されていないこと。

サーバー側の許可

これはnode.jsの場合なのですが、サーバーを自分で書く場合、レスポンスのヘッダーに

Access-Control-Allow-Origin

をつけてやる必要があります。自分で書かないといけないようですね。

  • Access-Control-Allow-Origin: https://test.co.jp
    特定のサイトを許可する
  • Access-Control-Allow-Origin: *
    全てのサイトを許可する(危険なのでプロダクトでは基本的には使わない)
  • Access-Control-Allow-Headers "X-Requested-With, Origin, X-Csrftoken, Content-Type, Accept"
    この辺は使うフレームワークにより異なるが許可するヘッダーを定義しておく。

まとめ

  1. そもそもwebはことなるオリジン間のデータのやり取りを許可していない
  2. ブラウザは単純リクエストを除いてプリフライトリクエストを行なっている
  3. サーバーからの応答で、メインリクエストを実行できるのかが決まる

Discussion