CORSって何?

# CORSって何?

W3C (World Wide Web Consortium)というWebの標準化団体が定めたSame-Origin Policy(SOP)を緩和するための仕組みです。

CORSが何か理解するためには、まず`HTTP cookie`と`Same-Origin Policy(SOP)`が何かを理解する必要があります。

## HTTP cookieとは

HTTP Cookie (Web Cookie、インターネット Cookie、ブラウザ Cookie、または単に Cookie とも呼ばれます) は、ユーザーが Web サイトを閲覧している間に Web サーバーによって作成され、**ユーザーの Web ブラウザによってユーザーのコンピュータまたはその他のデバイスに配置される**小さなデータ ブロックです。

Cookie は、Web 上で便利な、そして時には不可欠な機能を果たします。

これにより、Web サーバーはステートフル情報 (オンライン ストアのショッピング カートに追加された商品など) をユーザーのデバイスに保存したり、ユーザーの閲覧アクティビティ (特定のボタンをクリックしたり、ログインしたり、どのページにアクセスしたかを記録したりするなど) を追跡できるようになります。ユーザーが以前にフォーム フィールドに入力した名前、住所、パスワード、支払いカード番号などの情報を後で使用するために保存するために使用することもできます。

### Cookieの歴史

マジック クッキーは、1994 年 6 月にコンピューター プログラマーのルー モントゥリがウェブ通信でマジック クッキーを使用することを思いついたとき、すでにコンピューティングで使用されていました。
MCI は、サーバーが部分的なトランザクション状態を保持することを望まなかったので、代わりにその状態を各ユーザーのコンピュータに保存する方法を見つけるよう Netscape に依頼し、1994 年 10 月 13 日にリリースされた Mosaic Netscape のバージョン 0.9 ベータ版はCookie をサポートしました。

当時、Cookie の導入は一般に広く知られていませんでした。特に、Cookie はデフォルトで受け入れられ、ユーザーにはその存在が通知されませんでした。1996 年 2 月 12 日にフィナンシャル タイムズ紙が Cookie に関する記事を掲載してから、一般の人々が Cookie について知りました。同年、Cookie は特にプライバシーへの影響の可能性があるため、多くのメディアの注目を集めました。

## Same-Origin Policy(SOP)とは

セキュリティのための重要な仕組みで、異なるオリジン間でのリソースの共有を制限するものです。

このポリシーは、あるページ上の悪意のあるスクリプトが、そのページのドキュメント オブジェクト モデル (DOM) を介して別の Web ページ上の機密データにアクセスすることを防ぎます。

このメカニズムは、認証されたユーザー セッションを維持するために HTTP Cookieに大きく依存している最新の Web アプリケーションにとって特に重要です。これは、サーバーが HTTP Cookie 情報に基づいて動作し、機密情報を明らかにしたり、状態を変更するアクションを実行したりするためです。

データの機密性や完全性の損失を防ぐために、無関係なサイトによって提供されるコンテンツ間の厳密な分離をクライアント側で維持する必要があります。

同一生成元ポリシーは**スクリプトにのみ**適用されることに留意することが非常に重要です。

これは、画像、CSS、動的にロードされるスクリプトなどのリソースが、対応する HTMLタグ (フォントは例外) を介してオリジンを越えてアクセスできることを意味します。

### SOPの歴史

同一生成元ポリシーの概念は、Netscape 2.0 (Webブラウザアプリケーション) で JavaScript が導入された直後の 1995 年に Netscape Navigator 2.02 によって導入されました。
JavaScript により、Web ページ上でのスクリプト作成、特にドキュメント オブジェクト モデル (DOM) へのプログラムによるアクセスが可能になりました。このポリシーはもともと DOM へのアクセスを保護するために設計されましたが、その後、グローバル JavaScript オブジェクトの機密部分を保護するために拡張されました。

### origin(オリジン)とは?

URIの場合、スキーム、ホスト、ポートの組み合わせを指します。(他にもありますが、ここでは省略)

スキーム: http, https, ftp, file, data, chrome, chrome-extension, resource, blob, ws, wssなどのプロトコル
ホスト: ドメイン名やIPアドレス
ポート: 80, 443, 8080などのポート番号

### SOPが防げる攻撃の例

英語のWikiから引用します。

同一オリジン ポリシーは、認証されたセッションがオリジン間で再利用されることを防ぎます。次の例は、同一生成元ポリシーがないと発生する可能性のある潜在的なセキュリティ リスクを示しています。
ユーザーが銀行 Web サイトにアクセスしていて、ログアウトしていないとします。次に、ユーザーは、銀行サイトからデータを要求する悪意のある JavaScript コードが含まれる別のサイトにアクセスします。ユーザーはまだバンキング サイトにログインしているため、悪意のあるコードはユーザーがバンキング サイトで実行できるあらゆる操作を行う可能性があります。たとえば、ユーザーの最後のトランザクションのリストを取得したり、新しいトランザクションを作成したりすることができます。
これは、World Wide Web の本来の精神において、ブラウザは、セッション Cookie やプラットフォーム レベルの種類の Authorization リクエスト ヘッダーなどの認証詳細を銀行サイトのドメインに基づいて銀行サイトにタグ付けする必要があるためです。
銀行サイトの所有者は、悪意のあるサイトを訪問するユーザーの通常のブラウザでは、悪意のあるサイトからロードされたコードがバンキング セッション Cookie やプラットフォーム レベルの認証にアクセスすることを許可しないことを期待します。確かに JavaScript はバンキング セッション Cookie に直接アクセスできませんが、バンキング サイトのセッション Cookie を使用してバンキング サイトへのリクエストを送受信することはできます。同一オリジン ポリシーは、大多数のユーザーが準拠ブラウザの使用を選択することを前提として、セキュリティを重視したブラウザがオリジンを超えて応答への読み取りアクセスを拒否するための要件として導入されました。

## Cross-Origin Resource Sharing(CORS)とは

Cross-Origin Resource Sharing (CORS) は、ブラウザーが、オリジン間の HTTP リクエストを処理する方法を指定するための仕組みです。SOPは、オリジン間のリソース共有を制限するために設計されていますが、複数のサブドメインを使用するような大規模なWebサイトでは問題が発生することがあります。

そのため最新のブラウザでは、制御された方法で同一生成元ポリシーを緩和するための複数の手法をサポートしています。これらの手法の 1 つが CORS です。

CORSは、Web ページ上の制限されたリソースに、最初のリソースが提供されたドメイン外の別のドメインからアクセスできるようにするメカニズムです。

### CORSの歴史

クロスオリジンのサポートは、もともと、VoiceXML ブラウザによる安全なクロスオリジン データ要求を可能にするために、2004 年 3 月に Tellme Networks の Matt Oshry、Brad Porter、および Michael Bodell によって、VoiceXML 2.1 に含めることが提案されました。

このメカニズムは本質的に一般的なものであり、VoiceXML に固有のものではないと考えられ、主要なブラウザ ベンダーの参加を得た W3C の WebApps Working Group は、正式な W3C 勧告ステータスに向けて、NOTE を W3C Working Draft として正式化し始めました。

2006 年 5 月に、最初の W3C 作業草案が提出されました。2009 年 3 月に草案は「Cross-Origin Resource Sharing」に名前変更され、2014 年 1 月に W3C 勧告として承認されました。

## CORSの仕様

CORS プロトコルは、応答をオリジン間で共有できるかどうかを示す一連のヘッダーで構成されます。これは、W3Cのサイトで確認できますが、MWDの記述がわかりやすいのでそちらを中心に見ていきます。

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

CORSを可能にするには cross-origin sharing standard で定められたヘッダーを含んだリクエストをやり取りする必要があります。このヘッダーのルールはリクエストの種類によって2つのタイプに分けられます。

- Simple requests
- Preflighted requests

### Simple requests

通信によりサーバのデータが変更されない場合、ブラウザはリクエストを単純なリクエストとして処理します。

#### Simple requestsのルール

Simple Requestは、次の条件をすべて満たす必要があります。(他にもありますが、ここでは省略)

- リクエスト メソッドは、次のいずれかである必要があります。(通信によりサーバのデータが変更されないHTTPリクエスト)
  - GET
  - HEAD
  - POST
- HTTP ヘッダーは、次のいずれかである必要があります。
  - Accept
  - Accept-Language
  - Content-Language
  - Content-Type (ただし、次のいずれかである必要があります。)
    - application/x-www-form-urlencoded
    - multipart/form-data
    - text/plain

#### 通信フロー

異なるオリジンとの通信をする場合、ブラウザはリクエストに以下のようにOriginヘッダーを付与します。

```http
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
```

サーバーは、リクエストに対して以下のようにAccess-Control-Allow-Originヘッダーを付与します。

```http
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
```

![simple-req.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169789/b787577e-ccb1-a023-df88-4a5f4b48c4f8.png)


## Preflighted requests

通信によりサーバのデータが変更される場合、ブラウザはリクエストをプリフライトリクエストとして処理します。リクエストが安全に送信できるかどうかを判断するために、ブラウザはサーバーに対してOPTIONSメソッドを送信します。

### 通信フロー

異なるオリジンとの通信をする場合、ブラウザはリクエストに以下のようにAccess-Control-Request-Methodヘッダー、Access-Control-Request-Headersヘッダー、Originヘッダーを付与します。

```http
OPTIONS /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
```

サーバーは、リクエストに対して以下のようにAccess-Control-Allow-Originヘッダー、Access-Control-Allow-Methodsヘッダー、Access-Control-Allow-Headersヘッダー、Access-Control-Max-Ageヘッダーを付与します。

```http
HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
```

![preflight_correct.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169789/3b8167fb-0a6f-0c78-e193-a310fe9a912f.png)

## 参照

https://en.wikipedia.org/wiki/Same-origin_policy
https://en.wikipedia.org/wiki/HTTP_cookie

https://shukapin.com/infographicIT/origin-policy
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS