Same Origin Policy（同一オリジンポリシー）とCORS（オリジン間リソース共有）

CORS（オリジン間リソース共有）についてふんわりとしか理解できていなかったので、調べた。

## Originとは
まず初めにそもそもオリジンとは？

> 二つのページの [プロトコル](https://developer.mozilla.org/en-US/docs/Glossary/Protocol) 、 [ポート番号](https://developer.mozilla.org/en-US/docs/Glossary/Port)  (もしあれば)、 [ホスト](https://developer.mozilla.org/en-US/docs/Glossary/Host) が等しい場合、両者のページは同じオリジンです。
https://store.company.com

- `store.company.com` がドメイン
- `https://store.company.com:81` までがオリジン


## 同一オリジンポリシー（Same Origin Policy）
CORSに入る前に、まず、ブラウザは同一オリジンポリシーというものに従っている。

> **同一オリジンポリシー**とは、あるオリジンから読み込まれた文書やスクリプトについて、そのリソースから他のオリジンのリソースにアクセスできないように制限するものです。

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364773/09eb0c67-cb5f-eae8-951e-e64b3c78488f.png)


- URLで指定してアクセスしているサーバーから取得した結果からさらに他のリソースへアクセスする
- 同じオリジンのリソースにアクセスする場合は、Same-origin requests
- 別のオリジンのリソースにアクセスする場合は、Cross-origin requests 
- Cross-origin requests ができないように制御する

### 目的
> 同一オリジンポリシーはウェブのセキュリティにおける重要な仕組みであり、悪意ある行動を起こしかねないリソースの分離を目的としています。

- JavaScriptなどのクライアントスクリプトからサイトをまたがったアクセスを禁止するセキュリティ上の制限。
- つまり、異なるオリジンのアプリケーションから勝手にアクセスされないようにする
- 上記の図でいうと、`domain-a.com`は相手側（`domain-b.com`）の許可なしに、`domain-b.com`のリソースにアクセスすることができない。

### 同一オリジンポリシーの制限を受けるもの

* XMLHttpRequest
* Canvas
* Web Storage
* X-Frame-Options


### 同一オリジンポリシーの制限を受けないもの

- frame要素とiframe要素
- image要素
	- `<img src=“xxxx”>`
- script要素
	- `<script src=“xxx”><script>`
- css
- formのaction属性


## オリジン間リソース共有 (CORS)
同一オリジンポリシーでXMLHttpRequestについては相手側の許可があれば、同一オリジンでなくても通信ができるという規約がある。それがCORS。

- シンプルなリクエストの場合は [XMLHttpRequest](https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest)  を用いてHTTPリクエストを送ることが相手側の許可なしに可能
	- シンプルなリクエストについては後述。
- シンプルなリクエストの条件を満たさない場合については、  [OPTIONS](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/OPTIONS)  リクエストメソッドを用いた`プリフライトリクエスト`を送信して、サーバーからの認可が降りたら、実際のリクエストを送信できる

### シンプルなリクエスト
- 下記のメソッドのうちのいずれか
	*  [GET](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/GET) 
	*  [HEAD](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/HEAD) 
	*  [POST](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/POST) 
* 手動で設定できるヘッダー（[setRequestHeader()](https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/setRequestHeader)で設定するリクエストヘッダー）は下記のみ
	*   [Accept](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Accept) 
	*  [Accept-Language](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Accept-Language) 
	*  [Content-Language](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Language) 
	*  [Content-Type](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Type)  (但し、下記の要件を満たすもの)
* Content-Typeは下記のいずれか
	* application/x-www-form-urlencoded
	* multipart/form-data
	* text/plain


### プリフライトリクエスト

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364773/5a2ecba2-5cd3-e4b1-c7d4-9f4c5d661564.png)

- ブラウザはJavaScript コードで使用しているリクエストの引数に基づいて、プリフライトの送信が必要であることを判断する。
- プリフライトリクエスト（一部）
```
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
```
-  [Access-Control-Request-Method](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Request-Method)  ヘッダー
> 実際のリクエストが行われた際にどの HTTP メソッドが使用されるかをサーバーに知らせるために使用されます。プリフライトリクエストは常に OPTIONS であり、実際のリクエストとは同じメソッドを使用しないため、このヘッダーが必要です。	

-   [Access-Control-Request-Headers](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Request-Headers)  ヘッダー
> 実際のリクエストが行う際にどの  [HTTP ヘッダー](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers) を使用するかをサーバーに知らせます。

- プリフライトリクエストに対していのサーバーからのレスポンス（一部）

```
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
```

プリフライトリクエストを受け取ったAPIは、Access-Control-Request-MethodとAccess-Control-Request-Headersに対応する必要がある

- [Access-Control-Allow-Origin](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)  
> 指定された [オリジン](https://developer.mozilla.org/en-US/docs/Glossary/Origin) からのリクエストを行うコードでレスポンスが共有できるかどうかを示します。
	- リクエストのOriginに対応

-  [Access-Control-Request-Method](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Request-Method) 
> リソースにアクセスするときに利用できる1つまたは複数のメソッドを指定します。
	 - リクエストのAccess-Control-Request-Methodに対応

-  [Access-Control-Allow-Headers](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Headers) 
> 実際のリクエストの間に使用できる HTTP ヘッダーを示すために使用されます。
	- リクエストのAccess-Control-Request-Headersに対応
	
- Access-Control-Max-Ag
> プリフライトリクエストを再び送らなくてもいいように、プリフライトのレスポンスをキャッシュしてよい時間を秒数で与えます。この例では86400秒、つまり24時間です。

### 認証情報を含むリクエスト
- デフォルトではクロスオリジンに対するリクエストにはHTTP認証やクッキーなどの認証に用いられるリクエストヘッダは返信されない
- XMLHttpRequestのプロパティwithCredentialsをtrueにする必要がある。
	-  [XMLHttpRequest.withCredentials - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)
```
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send(null);
``` 

-  かつ、サーバーからのレスポンスヘッダでは [Access-Control-Allow-Credentials](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials) をtrueに設定する必要がある

- Access-Control-Allow-Originはワイルドカードではなくオリジンを指定しなければならない
> サーバーは Access-Control-Allow-Origin ヘッダーで “*” ワイルドカードではなくオリジンを指定**しなければなりません**。

## 参考
- [同一オリジンポリシー - Web セキュリティ | MDN](https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy)
- [なんとなく CORS がわかる…はもう終わりにする。 - Qiita](https://qiita.com/att55/items/2154a8aad8bf1409db2b)
- [オリジン間リソース共有 (CORS) - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)
- [体系的に学ぶ 安全なWebアプリケーションの作り方 第2版［固定版］　脆弱性が生まれる原理と対策の実践 | 徳丸 浩 | コンピュータ・IT | Kindleストア | Amazon](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%E5%9B%BA%E5%AE%9A%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/B07DVY4H3M)