-
Notifications
You must be signed in to change notification settings - Fork 0
MS_CORS
- 戻る(クロス ドメイン接続、HTTPヘッダ)
- CORS (Cross-Origin Resource Sharing)
- セキュリティ強化のHTTPヘッダ
- SameSite属性の件
CORS は、ブラウザの同一源泉ポリシー(Same-Origin Policy)による制限を、
サーバが明示的に緩和するための仕組みである。
-
Request
-
Origin… 源泉を表す URL。
-
-
Response
-
Cross-Origin-Resource-Policy…<script>や<img>などの要素を使用して
発行された他のオリジンからのリクエストに対する保護を事前に通知する。 -
Timing-Allow-Origin… Resource Timing API を許可するオリジン。 -
X-Permitted-Cross-Domain-Policies… アドビ製品によるページのレンダリングを許可。
-
-
Access-Control 系
| 方向 | ヘッダ |
|---|---|
| Request |
Access-Control-Request-Headers、Access-Control-Request-Method
|
| Response |
Access-Control-Allow-Origin、Access-Control-Allow-Credentials、Access-Control-Allow-Headers、Access-Control-Allow-Methods、Access-Control-Max-Age、Access-Control-Expose-Headers
|
移行メモ(正誤): 元 Wiki では
Access-Control-Expose-Headersが Request 側に分類されていたが、これはレスポンス ヘッダである (JavaScript から読み取ることを許可するレスポンス ヘッダ名を列挙する)。 上表では修正した。
先ず、同一源泉ポリシーと言う(同一オリジン ポリシーとも呼ばれる)仕組みがある。
-
コンテンツがブラウザに来る源泉(origin)に基づいて整理して、外部からの干渉を防ぐ仕組み。
-
以下の 3 つを一組としてすべて一致するとき同一の源泉(origin)とみなす。
- URL スキーム
- ホスト(IP や FQDN)
- ポート番号
-
厳密には異なるがクロスサイト、クロスドメインの制限と表記されることもある。
- Same-Origin Policy で通信が可能。
- また、Cookie の SameSite 属性などで利用されている。
移行メモ(正誤): 元 Wiki では 「セイムサイト(SameSite)= 同一生成元(Same-Origin)」としていたが、 この 2 つは別の概念である。
概念 一致を要求する要素 Same-Origin スキーム+ホスト+ポート(完全一致) Same-Site eTLD+1(登録可能ドメイン)+スキーム 例えば
https://a.example.comとhttps://b.example.comは Same-Site だが Cross-Origin である。 Cookie のSameSite属性は前者(Same-Site)の粒度、 CORS は後者(Same-Origin)の粒度で動作する。
CORS は、クロスサイト、クロスドメイン接続専用に用意された技術。
- ブラウザとサーバ間で、約束された Request / Response を使って、
そのドメインからのクロス ドメインの呼び出しを許可するか確認をおこなう。 - サーバが許可していれば
XMLHttpRequest(やfetch)を使用した
クロス ドメインの呼び出しをおこなう。
このように、ブラウザ・サーバの双方が CORS に対応している必要がある(ここが鬼門)。
補足: CORS は「ブラウザがレスポンスをスクリプトに渡すか」を制御する仕組みで、 サーバへのリクエスト到達自体を防ぐものではない(Preflight が発生しない 単純リクエストの場合、サーバの処理は実行される)。 従って、CORS はアクセス制御の代替にはならず、 副作用を伴う操作は必ず認証・CSRF 対策で守る必要がある。
- フレームワーク次第だが、基本的に、閉じられているので、空ける。
- ブラウザ側で問題が出るので、
Access-Control-Allow-*ヘッダを返すように設定する。 - ASP.NET の場合は、後述の設定を参考にする。
- jQuery など、ブラウザ上のライブラリは基本的に CORS をサポートしている。
- ブラウザによってサポート状況が異なり動作が変わる。
- 例えば、
fetchで以下の様なエラーが出る。
- 例えば、
Access to fetch at 'http://localhost:8888/...' from origin 'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
- 基本的に、CORS は閉じられているので、空ける。
- 特定サイトのみ許可する制御を加える。
- 対象:特定 GUI(Public Client)にのみアクセスを許可する。
- 対象外:不特定多数の Client に公開している WebAPI
CORS プロトコルが理解されているかどうかを確認する CORS リクエスト。
- CORS リクエストが受け入れられるかどうかを事前にチェックを行う。
- ある一定条件のリクエストを投げる際には事前に発生する。
(代表的なものに、POST かつapplication/jsonの例がある。) - その場合、サーバが以下を適切にレスポンスするように構成する必要がある。
| # | Header | 説明 |
|---|---|---|
| 1 | Access-Control-Allow-Origin |
許可されるオリジンの一覧 |
| 2 | Access-Control-Allow-Methods |
許可されるメソッドの一覧 |
| 3 | Access-Control-Allow-Headers |
許可されるヘッダの一覧 |
| 4 | Access-Control-Max-Age |
プリフライト情報のキャッシュを保持して良い時間 |
補足: Preflight が発生しない「単純リクエスト」の条件は、 メソッドが
GET/HEAD/POSTのいずれかで、 かつContent-Typeがapplication/x-www-form-urlencoded/multipart/form-data/text/plainのいずれかであること(+独自ヘッダを付けないこと)である。application/jsonが Preflight を誘発するのはこのためである。
-
シーケンス
- サイト A に Script を含むコンテンツを要求し、そのレスポンスを得る。
- 上記で得たコンテンツからサイト B に「Preflight request」
OPTIONS /test HTTP/1.1
Origin: http://site-a.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header, Content-Type
- 上記のレスポンス
Access-Control-Allow-Origin: http://site-a.example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-Custom-Header, Content-Type
Access-Control-Max-Age: 86400
- 上記で得たコンテンツからサイト B に「Main request」
ブラウザは事前にOriginとAccess-Control-Allow-Originの一致を確認する。
POST /test HTTP/1.1
Content-Type: text/json
X-Custom-Header: custom-data
- 上記のレスポンス
HTTP/1.1 200 OK
- 以下のように、curl で任意の
Originヘッダを指定してテストできる。
※ 送信するOriginヘッダは、ブラウザでは捏造不可能。
curl -H "Origin: http://example.com" --verbose http://localhost:8888/api/values/get
> GET /api/values/get HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.52.1
> Accept: */*
> Origin: http://example.com
>
< HTTP/1.1 200 OK
< Transfer-Encoding: chunked
< Content-Type: application/json; charset=utf-8
< Server: Microsoft-IIS/10.0
< X-Powered-By: ASP.NET
- Preflight request をテストする場合は以下のようにする。
curl -X OPTIONS -H "Origin: http://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Content-Type" \
--verbose http://localhost:8888/api/values/get
なお、IE8, 9 ではサポート状況が違うため(XDomainRequest)、
ライブラリのプラグイン内で条件分岐しているものがある。
補足(最新化):
XDomainRequestは IE8/9 固有の実装で、 IE10 以降および現行ブラウザではXMLHttpRequestLevel 2 /fetchに統一されている。 IE 自体のサポートも終了しているため、現在この分岐は不要である。
-
Access-Control-Allow-Credentials: trueが危ないレスポンス。 - 攻撃者が被害者の認証情報(Cookie)を任意のサイトに送信できる
(正確には、被害者のブラウザに認証情報付きでリクエストさせ、
そのレスポンスを攻撃者のスクリプトが読めるようになる)。
特に危険なのは、Origin ヘッダの値をそのまま
Access-Control-Allow-Origin に反射(echo back)する実装である。
- 危ないように見えるが実は危なくない。
-
Access-Control-Allow-Credentials: trueは機能しなくなる
(ワイルドカードと資格情報の併用はブラウザが拒否する)。 - ただし、任意のサイトにリクエストを送信することはできる。
- 実際の意味とは逆に「誰もいない」ではなく「全員」を意味する。
-
Access-Control-Allow-Credentials: trueが機能するので危険。
補足:
Origin: nullは sandbox 属性付き iframe やdata:URL、ローカル ファイルから送出される。 攻撃者は sandbox iframe を使って任意にnullを作れるため、Access-Control-Allow-Origin: nullは決して設定してはならない。
- クロス ドメイン接続
- セキュリティ強化のHTTPヘッダ
- ASP.NET Web API における設定
- オリジン間リソース共有 (CORS) - MDN
- Fetch Standard (CORS protocol)
Tags: セキュリティ, プログラミング, IT国際標準, 通信技術, .NET開発, .NET Core, ASP.NET, ASP.NET Web API
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。