CORS(Cross-OriginResourceSharing)メモ

# はじめに
CORS(Cross-OriginResourceSharing)メモ

# 参考
https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88%EF%BC%BB%E3%83%AA%E3%83%95%E3%83%AD%E3%83%BC%E7%89%88%EF%BC%BD-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8-%E6%B5%A9-ebook/dp/B07HHT54YR/ref=sr_1_1?crid=29Z1T7MLBUIWM&keywords=%E5%BE%B3%E4%B8%B8+%E6%9C%AC&qid=1697560290&sprefix=%2Caps%2C280&sr=8-1

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS

# CORSとは
同一オリジンポリシーの制限を回避して、異なるオリジンへのアクセスを許可できる仕組み

# 同一オリジンポリシーはブラウザの機能
* ブラウザは、JavaScriptであるオリジン（ドメイン、プロトコル、ポートが組み合わさったもの）からロードされたウェブページからは同じオリジンのリソースへのレスポンスしか受信しないように制限している
* それを回避して異なるオリジンのレスポンスを受信するようにした仕組みがCORS

## CORSの基本的な流れ
* ブラウザは異なるオリジンでもまずはサーバーにリクエストを送る
* レスポンスを JavaScript で取得できるかどうかは、サーバーの CORS 設定次第
* CORS ヘッダーがないと、サーバーはレスポンスを返しても、ブラウザがブロックする

* 単純リクエスト (GET, POST, HEAD で制限された場合) → そのままサーバーへリクエスト
* 非単純リクエスト (PUT, DELETE, カスタムヘッダーなど) → まず OPTIONS でサーバーに CORS 許可を確認 (プリフライトリクエスト)
* どちらにしても最終的にブラウザがレスポンスをチェックして、CORS ヘッダーがないとブロックする


| ヘッダー名                        | 役割                                      |
|---------------------------------|----------------------------------------|
| `Access-Control-Allow-Origin`    | 許可するオリジンを指定 (必須)          |
| `Access-Control-Allow-Methods`   | 許可する HTTP メソッドを指定            |
| `Access-Control-Allow-Headers`   | 許可するリクエストヘッダーを指定        |
| `Access-Control-Allow-Credentials` | `credentials: include` を許可する       |
| `Access-Control-Expose-Headers`  | JavaScript で取得可能なレスポンスヘッダーを指定 |
| `Access-Control-Max-Age`         | プリフライト (`OPTIONS`) のキャッシュ時間 |

※リクエストの内容によって、設定しなくてはいけないヘッダーは異なる

ブラウザはこれらのCORS ヘッダーをチェックして、JavaScript (fetch, XMLHttpRequest) でレスポンスを取得できるかどうかを決定します。

# 同一オリジンポリシー
同一オリジンからの情報読み出しは可能だが、クロスオリジン(同一オリジンではない)からの読み出しは基本できない。同一オリジンの定義は下記参照。

`プロトコル、ポート番号 (もしあれば)、FQDN = https://www.aaaa.co.jp:443`

https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy

# クロスオリジンからの読み出し
シンプルなリクエストの場合は`Access-Control-Allow-Origin: 読み出したいサーバの
FQDN`がサーバ(情報提供側)のレスポンスに含まれていると、クロスオリジンの情報を読み取ることができる。

例えばReactサーバとAPIサーバと別れていたら、APIサーバのレスポンスの`Access-Control-Allow-Origin`にはReaxtサーバのFQDNを指定しないといけない

# シンプルなリクエストとは
以下参照

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#%E5%8D%98%E7%B4%94%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88

# プリフライトリクエスト
* シンプルなリクエストの条件を満たさない場合、ブラウザはプリフライトリクエストというHTTPリクエストを送信する(外部へのアクセス前に)。これにより、ブラウザはサーバーからのレスポンスを確認し、実際のリクエストを安全に送信できるかどうかを判断します。

# シンプルなリクエストの条件を満たさない場合のクロスオリジンの情報を読み出す方法

プリフライトリクエストを正常に通過させ、クロスオリジンの情報を読み出すためには、サーバー側(情報提供側)で以下の設定を行う必要があります

* Access-Control-Allow-Origin:
    * このヘッダーで、どのオリジンからのリクエストを許可するかを指定します。

* Access-Control-Allow-Methods: 
    * どのHTTPメソッドを許可するかを指定します。例：POST, GET, PUT など。

* Access-Control-Allow-Headers: 
    * リクエストで許可されるヘッダーを指定します。特にカスタムヘッダーや、特定の認証に関連するヘッダーなど、シンプルなリクエストの条件にないヘッダーを使う場合は、ここで明示的に許可する必要があります。

上記3つは基本的に必須

* Access-Control-Max-Age: このヘッダーを使用して、ブラウザがプリフライトレスポンスをキャッシュする時間（秒単位）を指定できます。これにより、同じリクエストを繰り返し送る際のオーバーヘッドを削減できます。レスポンスしたほうが便利。

サーバー側でこれらのヘッダーを適切に設定することで、シンプルなリクエストの条件を満たさないクロスオリジンのリクエストでも、情報を正常に読み出すことができます。

# 認証情報を含むリクエスト
* デフォルトでクロスオリジンに対するリクエストにはクッキーなどの認証用に伴う情報はリクエストヘッダには自動的に送信されない。
* 認証用のヘッダを送信するようにするには
    * クライアント側ではXMLHttpRequestのプロパティwithCredentialsをtrueにセットする必要がある。
    * APIサーバ側(情報提供側)では`Access-Control-Allow-Credentails:true`を返す必要がある。