atmaバックエンド勉強会#4の資料です。
CORSをちゃんと理解する2021/07/07 #4 atma勉強会 nyk510
View Slide
質問です。
CORSって知ってますか?
CORSCross-Origin Resource Sharingオリジン間リソース共有
名前ぐらいは聞いたことある?エラーで見たことはある?よくわかんない?けどなんかヘッダーに設定したら直るやつ?
ちゃんと理解しましょう!
CORSの定義追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジン にある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。
オリジンて何?
オリジンURLのプロトコルとホスト(ドメイン)、ポートで識別されるもの全部が一緒だと同じオリジンとなる例えば https://hoge.com に対して● 同じ: https://hoge.com/foo/bar.html / https://hoge.com:443● 違う: http://hoge.com / https://api.hoge.com
CORSの定義追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーション(ex: フロントエンド)に、異なるオリジン にある選択されたリソース (ex: バックエンド)へのアクセス権を与えるようブラウザーに指示するための仕組みです。
CORSの定義からわかること● 特定のオリジンのアプリから、別のオリジンのデータ(リソース)を取ってくる権限を定めたものである。● ブラウザーの仕組みである○ 例えば terminal からのアクセスは関係ない
なんでこんなのがあるの?● セキュリティ的観点から同じオリジン以外の情報を取ってこれないようにしているから● 取ってこようとしている先のオリジンが許可した時だけデータのやり取り(リソース共有)ができるホワイトリスト方式になっている。以下の説明では● ブラウザで表示されているオリジン: Alice● 異なるオリジン: Blobとして説明します。
ブラウザは、どうやって許可されているかを知るの?● ブラウザは一度普通にBobへとリクエストを送りBobはレスポンスを返す● ブラウザはレスポンス内の Access-Control-Allow-Origin ヘッダーをみる○ リクエスト元の Origin がこの中に入っていれば許可されたとみなす。○ ワイルドカード * 指定も出来る。この場合何でも許可されたとみなす。○ それ以外は許可されていないリクエストとみなす。● 許可されている時○ レスポンスを展開して js からアクセス可能● 許可されていない時○ ブラウザが強制的に処理を止めてエラーになる. js からは「何かしらのエラーが起こった」しかわからない(これはセキュリティのため)
Bob から見ると…● 自分を呼び出してもオッケーなサイトを Access-Control-Allow-Origin に入れる● するとそれ以外のオリジンでは、ブラウザからBobの情報を参照できない● すくなくともブラウザでアクセスして悪さする外部サイトの脅威を減らせて良い
アクセス許可の方法● 単純リクエスト● プリフライトリクエスト
単純リクエスト● 相手サーバ Bob に副作用を起こさないようなリクエスト● 先のフローと同様のやり方で許可を判定する● method: GET/HEAD/POST● content-type: application/x-www-formurlencoded, multipart/form-data,text/plan
プリフライトリクエスト● 単純リクエストでないものが該当 ・ ex:) POSTで json を送りたいフロー● 許可を取るリクエスト (OPTION) を自動的にブラウザが Bob へ送信○ 今からこういうことするのでオッケーですかというお伺い○ これがプリフライトリクエスト● Bobは要求に従って何を許可するかを返信○ ex). POSTはOK / application/json はOK● ブラウザは許可内容をみる (Bobは何がOKって言っている?)○ やりたいリクエストが許可なら、Bobへ本体のリクエストを送信○ 許可されていなければエラーにする(jsからは失敗内容はわからない)
ブラウザからのリクエストとレスポンス● 何故か method が単数形と複数形あるがこれはお伺い建てるのはひとつだけだから● リクエストだけ origin は origin なのは謎要求 リクエストヘッダー レスポンスヘッダーmethodに対する許可 Access-Control-Request-Method Access-Control-Allow-Methodsヘッダーに対する許可 Access-Control-Requests-Header Access-Control-Allow-Headersオリジンに対する許可 Origin Access-Control-Allow-Origin
具体例を見ましょう。
例: ぐるぐるフロントエンド: https://guruguru.scienceバックエンド: https://api.guruguru.scienceこれらは別 Origin なので Access-Control-Allow-Origin をバックエンド側に仕込んでいないとフロントをブラウザで開いた時バックエンドの情報は表示できない。
例: ぐるぐる・単純リクエストhttps://api.guruguru.science/competitions/17/ブラウザからAPIへ送信しているリクエストヘッダーAPIからブラウザへ返信されたレスポンスヘッダー
例: ぐるぐる・単純リクエストhttps://api.guruguru.science/competitions/17/リクエストの method が GET なので単純リクエストとしてブラウザで処理される。
例: ぐるぐる・単純リクエストhttps://api.guruguru.science/competitions/17/APIが allow-origin に www.guruguru.science を入れている → ブラウザで表示OK
例: ぐるぐる・プリフライトつきリクエストログインページ: https://api.guruguru.science/auth/login/POSTでかつusername/passwordを送信するため単純ではない。おさらい● はじめOPTIONによるプリフライトで確認● 確認がとれれば本体のPOSTを送信
例: ぐるぐる・OPTIONによるプリフライトで確認ブラウザはこれから何を送ろうとしているかをOPTIONをつかってお伺い (プリフライトリクエスト)この場合だと「MethodはPOST / ヘッダーには content-type / オリジンは https://www.guruguru.science ですがよろしいでしょうか」
例: ぐるぐる・OPTIONによるプリフライトで確認APIはブラウザの各種 requests に対して何を許可しているかを返す。API「POSTはOK・ヘッダーも content-type はオッケーで、オリジンもOKだよ!」
例: ぐるぐる・確認がとれれば本体のPOSTを送信今回の場合別オリジン(API)から許可がもらえたので本体のPOST処理を送信。もう許可はもらえているのでこのリクエストにAccess-Control-Request 系のヘッダーはない。
まとめ● CORSはオリジンの違うサーバにたいしてブラウザからアクセスするときの制御に関する仕組みである。● リクエストの種類によってプロトコルが異なる。
参考資料● https://developer.mozilla.org/ja/docs/Web/HTTP/CORS● 安全なウェブアプリケーションの作りかた・3.3章