Skip to content

MS_CORS

nishi_74322014 edited this page Aug 3, 2026 · 1 revision

CORS (Cross-Origin Resource Sharing)

概要

CORS は、ブラウザの同一源泉ポリシー(Same-Origin Policy)による制限を、
サーバが明示的に緩和するための仕組みである。

詳細

HTTPヘッダ

  • 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-HeadersAccess-Control-Request-Method
Response Access-Control-Allow-OriginAccess-Control-Allow-CredentialsAccess-Control-Allow-HeadersAccess-Control-Allow-MethodsAccess-Control-Max-AgeAccess-Control-Expose-Headers

移行メモ(正誤): 元 Wiki では Access-Control-Expose-Headers が Request 側に分類されていたが、これはレスポンス ヘッダである (JavaScript から読み取ることを許可するレスポンス ヘッダ名を列挙する)。 上表では修正した。

同一源泉ポリシー

先ず、同一源泉ポリシーと言う(同一オリジン ポリシーとも呼ばれる)仕組みがある。

  • コンテンツがブラウザに来る源泉(origin)に基づいて整理して、外部からの干渉を防ぐ仕組み。

  • 以下の 3 つを一組としてすべて一致するとき同一の源泉(origin)とみなす。

    • URL スキーム
    • ホスト(IP や FQDN)
    • ポート番号
  • 厳密には異なるがクロスサイト、クロスドメインの制限と表記されることもある。

セイムサイト(SameSite)/同一生成元(Same-Origin)

移行メモ(正誤): 元 Wiki では 「セイムサイト(SameSite)= 同一生成元(Same-Origin)」としていたが、 この 2 つは別の概念である。

概念 一致を要求する要素
Same-Origin スキーム+ホスト+ポート(完全一致)
Same-Site eTLD+1(登録可能ドメイン)+スキーム

例えば https://a.example.comhttps://b.example.comSame-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

ポイント

Preflight request

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-Typeapplication/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」
    ブラウザは事前に OriginAccess-Control-Allow-Origin の一致を確認する。
POST /test HTTP/1.1
Content-Type: text/json
X-Custom-Header: custom-data
  • 上記のレスポンス
HTTP/1.1 200 OK

curlでCORS設定を確認

  • 以下のように、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 以降および現行ブラウザでは XMLHttpRequest Level 2 / fetch に統一されている。 IE 自体のサポートも終了しているため、現在この分岐は不要である。

危険な設定

Access-Control-Allow-Credentials: true

  • Access-Control-Allow-Credentials: true が危ないレスポンス。
  • 攻撃者が被害者の認証情報(Cookie)を任意のサイトに送信できる
    (正確には、被害者のブラウザに認証情報付きでリクエストさせ、
    そのレスポンスを攻撃者のスクリプトが読めるようになる)。

特に危険なのは、Origin ヘッダの値をそのまま
Access-Control-Allow-Origin に反射(echo back)する実装である。

Access-Control-Allow-Origin: *

  • 危ないように見えるが実は危なくない。
  • Access-Control-Allow-Credentials: true は機能しなくなる
    (ワイルドカードと資格情報の併用はブラウザが拒否する)。
  • ただし、任意のサイトにリクエストを送信することはできる。

Access-Control-Allow-Origin: null

  • 実際の意味とは逆に「誰もいない」ではなく「全員」を意味する。
  • Access-Control-Allow-Credentials: true が機能するので危険。

補足: Origin: null は sandbox 属性付き iframe や data: URL、ローカル ファイルから送出される。 攻撃者は sandbox iframe を使って任意に null を作れるため、 Access-Control-Allow-Origin: null は決して設定してはならない

参考


Tags: セキュリティ, プログラミング, IT国際標準, 通信技術, .NET開発, .NET Core, ASP.NET, ASP.NET Web API

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally