CORSをちゃんと理解する
今回はCORSについてまとめたいと思います。私はよくサーバー側の設定を忘れて、ブラウザに怒られたりしてますが、今ひとつ理解できず、コピペして終わってました。Rails
のapiモード
でアプリを作る時とかも、よくわからずgem rack-cors
とか書いてました。最近、FetchAPI
について学ぶ機会があって、ブラウザからのhttp
通信についてちゃんと調べようと思ったのがきっかけでCORSについてもまとめてみました。
corsとは?
CORS(Cross-Origin Resource Sharing)は異なるオリジン間での通信を許可する仕組み。CSRFなどのセキュリティ面から、XMLHttpRequest
やFetchAPI
などのhttp通信は同一オリジンポリシーに従います。従ってオリジンが異なる場合はそれを許可するための、適切なcorsに関するヘッダーが必要になってきます。
オリジンとは?
オリジン = ドメイン + プロトコル + ポート番号
https://domain-a.com
みたいな部分がオリジンですね。つまり、https://domain-a.com
からhttps://domain-b.com
への通信はデフォルトでは許可されず、corsによる設定が必要になるという事です。
ではcorsの設定についてみていきます。
プリフライトリクエスト
後述する特定の条件以外の場合は、プリフライトリクエスト
と呼ばれるリクエストを最初に行い、あらかじめサーバーがリクエストに応答可能か確認を行います。httpのOPTIONS
リクエストによって、これを行います。
リクエスト
OPTIONS / HTTP/1.1 Origin: https://domain-a.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-Custom-Header, Content-Type
通信を行いたいメソッドや、ヘッダーをサーバーに対して提示します。Access-Control-Request-Headers
に関しては後述の単純リクエストで許可されるヘッダー以外を指定します。
レスポンス
HTTP/1.1 204 No Content Access-Control-Allow-Origin: http://domain-a.com Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-Custom-Header, Content-Type Access-Control-Max-Age: 86400
レスポンスには許可するオリジン、メソッド、ヘッダー情報が含まれます。Access-Control-Allow-Origin
に関してはワイルドカードの使用が可能なので、全てを許可する場合は、
Access-Control-Allow-Origin: *
と書くことが可能です。
Access-Control-Max-Age
は、プリフライトリクエストの結果をキャッシュしておける上限時間です。
単純リクエスト
以下のいずれかの条件を満たす場合は、プリフライトリクエストを送らずに直接http通信を行うことが可能です。
逆に言えば、この条件を満たさない場合は、全てまず、プリフライトリクエストを行わなければなりません。
以下のメソッドのいずれかである。
GET, HEAD, POST
以下のヘッダーのみを含む。
Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width
Content-Typeヘッダーは以下のみ。
application/x-www-form-urlencoded, multipart/form-data, text/plain
リクエストに使用される
XMLHttpRequestUpload
にイベントリスナーが登録されていない。リクエストに
ReadableStream
オブジェクトが使用されていない。
資格情報(認証)
認証を行うためにCookieをヘッダーに含めて送信したい場合は多くあると思います。デフォルトではヘッダーにCookieは含めないので、リクエスト時に設定が必要です。
XMLHttpRequest
の場合
const xhr = new XMLHttpRequest(); xhr.withCredentials = true;
FetchAPI
の場合
fetch('https://domain-a.com', { mode: 'cors', credentials: 'include', });
これにより、リクエストヘッダーにCookie
ヘッダーが含まれるようになります。
レスポンスに次のヘッダーが含まれば、許可されたことになります。
Access-Control-Allow-Credentials: true
これはプリフライトリクエストの場合でも、実際のリクエストの場合にも(もちろん単純リクエストの場合も)含まれます。プリフライトリクエストの場合は、実際のリクエストにCookieを含められるかどうか、実際のリクエストの場合は、それをブラウザで利用して良いかを定めています。つまり、実際のリクエストでこれがtrue
でなかった場合は、ブラウザによって無視されるということになります。
注意点としては、資格情報を送る場合はAccess-Control-Allow-Origin
にワイルドカードを設定できません。特定のオリジン名を指定する必要があります。
参考
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS
http://www.tohoho-web.com/ex/cors.html
https://qiita.com/att55/items/2154a8aad8bf1409db2b