APIを実装するとなったときにCORS(オリジン間リソース共有)というワードに出会い、「CORSって何だ?」と思ったのでまとめます。(恥かしいことながらこのとき初めて知りました)
この記事で書いてあること
・ざっくりHTTP通信とは
・同一オリジンポリシーとは
・CORSが何かを理解する
・LaravelでのCORS設定方法
まずCORSの話に入る前に、前提としてHTTP通信とは何かということをざっくり説明します。
そんなの知ってるよという方は読み飛ばしてください。
HTTPとは通信プロトコルの1つです。
プロトコルとは2者間で通信をするときに「こういう感じでやり取りしましょう」といったお決まりごとみたいなものですね。
HTTP以外にもよく聞くところだと、「SMTP」、「TCP/IP」、「FTP」など様々なプロトコルが存在します。
ではHTTPはどういった通信をしているかと言うと、
クライアント(ブラウザ等)はサーバーに対して「このページが見たい」というリクエストを要求します。
その要求に対してサーバーが「こちらがそのページです」とレスポンスを返します。
図で表すとこんな感じです。
普段は何も意識せずウェブページを見ているかと思いますが、こういうやり取りが高速で行われています。
HTTPについてはもっと説明すべきことがあるのですが、今回は本題ではないのでこの辺にしておきます。
もっと知りたいという方は下記を参考にしてください。
CORSの概要
先にCORSとは何なのか簡単に説明します。
同一オリジンポリシーの元、異なるオリジンからのリソースへのアクセスは制限されていますが、異なるオリジンからのリクエストでもアクセスできるようにした仕組みです。
聞き慣れないワードもあると思いますのでそれぞれ解説していきます。
オリジンとは
まずオリジンとは下記のことを指します。
スキーム(プロトコル) + ドメイン(ホスト) + ポート
例)http + example.com + 80
同一オリジンと異なるオリジンの違いを見ていきましょう。
http://r-tech14.com/example1
http://r-tech14.com/example2
スキームとドメインが同じなので同一オリジン
http://r-tech14.com:80
http://r-tech14.com
既定で80番ポートはHTTPコンテンツを配信するため同一オリジン
http://r-tech14.com/example1
https://r-tech14.com/example2
スキームが異なるため同一オリジンではない
http://www.r-tech14.com
http://api.r-tech14.com
サブドメインが含まれるとドメインが異なるため同一オリジンではない
http://r-tech14.com
http://r-tech14.com:8080
ポートが異なるため同一オリジンではない
同一オリジンポリシー
異なるオリジンからのリソースへのアクセスを制限するウェブのセキュリティにおける重要な仕組みです。
他のオリジンからのアクセスを何でも許可していると、悪意あるユーザーがスクリプトを埋め込んだりしてリソースに対して攻撃されてしまいます。
同一オリジンポリシーによって安全性はもたらされることはメリットですが、デメリットも存在します。
柔軟性に乏しい点ですね。
Web開発を行うにあたり、異なるオリジンにあるリソースへアクセスしたいケースもあるかと思います。
例えば、Webサービスがサブドメインごとにコンテンツが分かれていて、別のサブドメインのコンテンツにアクセスしたいケースなどです。
こういったことを解決するためにCORSを設定してクロスオリジンからのアクセスも許可してあげるようにします。
CORS機能概要
CORSを設定してあげることでブラウザから情報を読み取ることが許可されているオリジンをサーバー側で指定することできます。
CORSという文脈ではリクエストの種類に単純リクエストとプリフライトリクエストの2つが存在します。
単純リクエスト
以下のすべての条件を満たすものです。
- GET、POST、HEADメソッドのうちの1つであること
- 設定できるヘッダーはAccept、Accept-Language、Content-Language、Content-Type
- Content-Typeヘッダーがapplication/x-www-form-urlencoded、multipart/form-data、text/plain のいずれかに設定されている場合
一方でプリフライトリクエストは単純リクエストではない場合に送信されます。
プリフライトリクエスト
OPTIONS
メソッドによるリクエストを他のドメインにあるリソースに向けて送り、実際のリクエストを送信しても安全かどうかを確かめます。
プリフライトリクエストが許可されると実際のリクエストが送信されます。
逆に許可されないと実際のリクエストはブロックされます。
CORS設定してないオリジンからのリクエスト
CORS設定しているオリジンからのリクエスト
クライアント側からクロスオリジンへのリクエストの際はOrigin
ヘッダーが自動で付与されます。
サーバー側はOrigin
ヘッダーのオリジンがCORSに設定されているかを確認し、CORSに設定されていればAccess-Control-Allow-Origin
というレスポンスヘッダーを返します。
しかし、Access-Control-Allow-Origin: *
と設定されていると、リソースに対してすべてのドメインからアクセスできることを意味します。
これではCORSを設定している意味がないので、Access-Control-Allow-Origin: http://r-tech14.com
と返してあげることでhttp://r-tech14.com
以外からのアクセスを制限します。
LaravelでのCORS設定
最後にLaravelではどのように設定するのかを解説します。
laravel-corsというライブラリが存在し、簡単に設定することが可能です。
Laravel7.*以降であればデフォルトでサポートされています。
設定ファイルはconfig/cors.phpです。
デフォルトではガバガバの状態なので利用する際はしっかりアクセス制限できるようにそれぞれの項目を指定していきます。
paths | Access-Control-Expose-Headersを設定するパス 例: ['api/*'] |
allowed_origins | 許可するリクエストオリジンの設定 例: *.mydomain.com |
allowed_origins_patterns | 許可するリクエストオリジンを正規表現 を使用して設定します |
allowed_methods | 許可するリクエストメソッド |
allowed_headers | Access-Control-Allow-Headersの表示 |
exposed_headers | Access-Control-Expose-Headersの表示 |
max_age | Access-Control-Max-Ageの値 |
supports_credentials | Access-Control-Allow-Credentialsの表示 |
仕事でCORSのエラーにハマり、その時CORSって何だ?ってなったのでこれを気にまとめてみました。
まだまだウェブの世界は知らないことが多いので学び続けます。
最後までご覧いただきありがとうございます。
コメント