CORSついてまとめてみました。
自分が分かるように引用してまとめたので間違いなどがあれば指摘してください。
CORSとは
CORS(Cross-Origin Resource Sharing) :日本語訳すると「オリジン間リソース共有」。
「同一オリジンポリシー (Same-Origin Policy)」というポリシーによって設けられた制限を緩めるもので異なるオリジンからのリクエストでもアクセスできるようにした仕組み。
具体的に書くと追加のHTTPヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンに選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みを指す。
CORSはなぜ必要?
異なるオリジンからのリソースを読み込もうとした場合、ブラウザは以下のようなエラーをコンソールに出力し、読み込みを禁止する。
これはブラウザが、同一オリジンポリシーと呼ばれるセキュリティ制約を持っており、異なるオリジンからのリソースへのアクセスを制限するためである。この制限は、異なるオリジンからのクロスサイトスクリプティング攻撃(XSS)やクロスサイトリクエストフォージェリ(CSRF)などのセキュリティ上のリスクを軽減するため。
・XSS (クロスサイトスクリプティング攻撃)
ユーザーが Web サイトにアクセスすることで不正なスクリプトが Client (Web ブラウザ) で実行されてしまう脆弱性。
被害例は、Cookie内のセッション情報を抜き取られて不正ログインを行われる、など。
・CSRF (クロスサイトリクエストフォージェリ)
Web アプリケーションのユーザーが、意図しない処理を Web アプリケーション (Web Server) 上で実行される脆弱性。通称「しーさーふ」。
被害例は、本来はログインしたユーザーしか実行できない記事の投稿処理を勝手にされる、など。
このように、同一オリジンポリシーがあることによって悪意ある攻撃から情報を守ることができるようになったが、一方でAJAXの普及・発展により、異なるオリジン(主に異なるホスト)のAPIを呼び出したいという動機が生まれた。
このニーズに応えるため、CORSが考案された。
CORSの基本特性について
CORSが提供する機能
・クロスオリジン(異なるオリジン)のリソースアクセスを提供
・オリジン単位のアクセス制御を提供
過去のコンテンツとの後方互換性を提供
・従来動作していたサイトがCORSのブラウザ元でも動作する
・従来の(CORSを使っていない)サイトの性能劣化はほとんどない
・従来セキュリティ上問題のないサイトがCORSのブラウザの元でも安全に動作する
HTTPヘッダを用いたアクセス制御
・リクエストヘッダ: Origin、Access-Controll-Request-XXXXというヘッダを使用する
・レスポンスヘッダ: Access-Controll-Allow-XXXXというヘッダで許可を与える
単純リクエストについては無条件でリクエストを送信して、レスポンスヘッダによりJSがリソースを受け取れるか否かを判断する。
単純ではないリクエストについてはプリフライトリクエストによりリクエスト送信の許可を得る。
単純リクエストとプリフライトリクエスト(単純ではないリクエスト)について
CORSではリクエストの種類が単純リクエストとプリフライトリクエスト(単純ではないリクエスト)の2種類に分けられている。
CORSによって異なるオリジンからのリソースの読み込みを許可する場合の通信フローはこのHTTPリクエストの種別(単純リクエスト or プリフライトリクエスト)によって異なる。
プリフライトリクエストは、特定の条件を満たすリクエストに対して事前の許可を要求するために使用される。シンプルリクエストは、プリフライトなしで直接アクセスを許可されるリクエストのタイプになる。
単純リクエスト
「単純リクエスト」とは、以下の1、2、3の条件の内のいずれかをすべて満たすもの。
1.許可されているメソッドのうちいずれかであること
・GET ・HEAD ・POST
2.手動で設定できるリクエストヘッダは以下のいずれかであること(ユーザエージェントによって自動的に付与されるヘッダーを除く)
・Accept ・Accept-Langage ・Content-Langage ・Content-Type
3.Content-Typeヘッダは以下のいずれかであること
・application/x-www-form-urlencoded ・multipart/form-data ・text/plain
これら1、2、3の条件の内のいずれか全て満たすものを単純リクエストと定義されている。
単純リクエストの場合の通信フロー
① クライアントは https ://aaa.com へアクセス。
② サーバ aaa.com はレスポンスを返す。
③ ブラウザは追加コンテンツを取得するため、https ://bbb.com へアクセス。
Originヘッダにて、呼び出し元のオリジン(https ://aaa.com/)を指定する。
④ サーバ bbb.com はAccess-Control-Allow-Originヘッダに表示を許可する呼び出し元として https ://aaa.com/ を指定し、コンテンツを送信。
プリフライトリクエスト(単純ではないリクエスト)
プリフライトリクエスト : リクエスト送信前にOPTIONSメソッドによるHTTPリクエストを他のドメインにあるリソースに向けて送り、実際のリクエストを送信しても「該当のリクエストは、安全に送信できるリクエストであるか?」を判断するためのHTTPリクエスト。
プリフライトリクエストは、シンプルリクエストの条件を満たさない場合に使用されます。以下のいずれかの条件が該当する場合、ブラウザは事前の許可を要求するためにプリフライトリクエストを送信する。
- リクエストメソッドがGET、HEAD、POSTのいずれでもない場合。
- Content-Typeヘッダーが上記のシンプルリクエストの条件を満たさない場合。
- カスタムヘッダーがリクエストに含まれる場合。
カスタムヘッダー(Custom Header)は、HTTPリクエストやレスポンスのヘッダーに、ユーザーが独自に定義した任意の情報を含めるために使用されるヘッダー。
特定の要件やコンテキストに合わせて、リクエストやレスポンスに追加の情報を提供するために使用される。例えば、APIの認証トークンやセッションID、カスタムメタデータなどをカスタムヘッダーに含めることができる。これにより、クライアントとサーバー間での追加の情報のやり取りが可能になる。
以下はカスタムヘッダー "X-Custom-Header" を含むHTTPリクエストの例。
GET /api/data HTTP/1.1
Host: example.com
X-Custom-Header: CustomValue
この例では、クライアントが "X-Custom-Header" ヘッダーを追加してカスタムの値 "CustomValue" をサーバーに送信している。サーバー側では、このカスタムヘッダーを読み取り、必要に応じて適切な処理を行うことができる。
プリフライトリクエストの場合の通信フロー
① クライアントは https ://aaa.com へアクセス。
② aaa.com のサーバはレスポンスを返す。
③ ブラウザは https ://bbb.com へリクエスト送信して問題ないかを確認。(呼び出し元ドメインや送信予定のリクエストのメソッド・ヘッダ情報を送信)
④ サーバ bbb.com は③の条件のリクエストを受け入れOKの場合、受け入れ可能条件を送信。
⑤ ブラウザは追加コンテンツ取得のため、https ://bbb.com へアクセス。
⑥ サーバ bbb.com はAccess-Control-Allow-Originヘッダに表示を許可する呼び出し元として https ://aaa.com/ を指定し、コンテンツを送信。
CORSに関連するHTTPヘッダの例
CORSの設定
異なるオリジンのサーバからのアクセスを許可するには、サーバ側でCORS設定を適切に構成する必要がある。使用しているサーバの種類や言語によって異なるが以下は一般的な手順。
1.サーバ側のレスポンスヘッダーにAccess-Control-Allow-Originを追加します。これは、許可するオリジンを指定するためのヘッダーです。(必須)
Access-Control-Allow-Origin: https://example.com
上記の例では、https://example.comというオリジンからのアクセスを許可しています。もしすべてのオリジンからのアクセスを許可したい場合は、以下のようにワイルドカード*を使用します。(セキュリティ上は非推奨)
Access-Control-Allow-Origin: *
2.必要に応じて、Access-Control-Allow-Methodsヘッダーを使用して許可するHTTPメソッドを指定します。
Access-Control-Allow-Methods: GET, POST, PUT
上記の例では、GET、POST、PUTメソッドを許可しています。
3.必要に応じて、Access-Control-Allow-Headersヘッダーを使用して許可するリクエストヘッダーを指定します。
Access-Control-Allow-Headers: Content-Type, Authorization
上記の例では、Content-TypeとAuthorizationヘッダーを許可しています。
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://example.com"
Header set Access-Control-Allow-Methods "GET, POST, PUT"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
</IfModule>
location / {
add_header Access-Control-Allow-Origin https://example.com;
add_header Access-Control-Allow-Methods "GET, POST, PUT";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
}
これらの設定をサーバ側で行うことで、異なるオリジンからのアクセスを許可することができます。ただし、セキュリティ上のリスクを最小限に抑えるために、必要なオリジンとリクエストヘッダー、クレデンシャルの設定を慎重に行うことが重要です。
参考記事