HTTPQUERY
日本語

Access-Control-Allow-Origin

使い方

注意

CORS(Cross-Origin Resource Sharing、オリジン間リソース共有)は、サーバーが明示的にアクセスを許可しない限り、別のオリジンから配信されたレスポンスを Web ページが読み取るのをブロックするブラウザの仕組みです。ブラウザはクロスオリジンのリクエストに Origin ヘッダーを自動的に設定します。JavaScript から Origin ヘッダーを変更することはできません。

すべての CORS のレスポンスには Access-Control-Allow-Origin が含まれ、特定のオリジンのフロントエンドコードがそのレスポンスを読み取ってよいかをブラウザに伝えます。一致する値がなければ、ブラウザはレスポンスが JavaScript に届くのをブロックします。

アクセスを許可するサーバーには 3 つの選択肢があります。ワイルドカード、明示的なオリジン、null です。本番環境のほとんどの API は、受信した Origin リクエストヘッダーを許可リストと照合して動的にオリジンを選びます。オリジンが一致すると、サーバーはその値をそのまま返します。リクエストに応じてレスポンスが変わるため、キャッシュがオリジンごとに別々のコピーを保存できるよう Vary: Origin ヘッダーが必要です。

CORS を引き起こすもの

別のオリジンへの fetch() や XMLHttpRequest はいずれも CORS の強制を引き起こします。@font-face によるフォントの読み込み、WebGL のテクスチャ、クロスオリジンの画像に対する canvas.drawImage() も CORS のチェックを引き起こします。カスタムヘッダーを伴うリクエスト、PUT、DELETE、PATCH のような単純ではないメソッド、application/json の Content-Type は、実際のリクエストを送る前にプリフライトの OPTIONS リクエストを引き起こします。リンクのクリックやブラウザでのページ読み込みといった通常のナビゲーションは CORS を引き起こしません。

*(ワイルドカード)

任意のオリジンがレスポンスを読み取ることを許可します。ワイルドカードが有効なのは、認証情報を伴わないリクエストに限られます。

Access-Control-Allow-Origin: *

注意

ワイルドカードは認証情報を伴うリクエストと両立しません。Access-Control-Allow-Credentials が true の場合、サーバーは明示的なオリジンを返さなければなりません。

明示的なオリジン

スキーム、ホスト名、任意のポートからなる単一のオリジンの値です。これは、既知の呼び出し元に限定した API における標準的な手法です。

Access-Control-Allow-Origin: https://example.com

1 つのレスポンスで許可できるオリジンは 1 つだけです。複数のオリジンに対応するサーバーは、Origin リクエストヘッダーを調べ、一致した値を返し、レスポンスに Vary: Origin を加えます。

null

不透明な、あるいはプライバシー上センシティブなオリジンを表します。一部のサンドボックス化された文書やローカルのファイル URL は、自身のオリジンとして null を送ります。

Access-Control-Allow-Origin: null

注意

null で応答することは推奨されません。サンドボックス化された iframe 内の悪意ある文書も null オリジンを持つため、この値は容易に偽装できます。

例

サーバーが要求元のオリジンを動的に反映し、正しいキャッシュ動作のために Vary ヘッダーを含めます。

Access-Control-Allow-Origin: https://example.com
Vary: Origin

任意の呼び出し元に静的アセットを配信する公開 CDN は、ワイルドカードを使います。

Access-Control-Allow-Origin: *

認証情報を伴うクロスオリジンのレスポンスは、明示的なオリジンと認証情報のヘッダーを組み合わせます。

Access-Control-Allow-Origin: https://dashboard.example.re
Access-Control-Allow-Credentials: true
Vary: Origin

トラブルシューティング

ブラウザがレスポンスのオリジンを要求元のページと照合できない場合、クロスオリジンのリクエストは失敗します。

コンソールに「No ‘Access-Control-Allow-Origin’ header is present on the requested resource.」と表示される。サーバーがこのヘッダーをまったく含めていません。サーバー側の CORS 設定が、その特定のルートと HTTP メソッドに適用されていることを確認してください。nginx では add_header ディレクティブが正しい location ブロック内にあることを確認します。Apache では Header set が該当する や の中にあることを確認します。ブラウザの挙動と切り分けるには curl でテストします。curl -v -H “Origin: https://example.com” https://api.example.re/data のようにします。

ワイルドカード * が認証情報を伴うリクエストで機能しない。ブラウザは、Access-Control-Allow-Origin: * と Access-Control-Allow-Credentials: true を組み合わせたレスポンスを拒否します。対処法は、受信した Origin ヘッダーを読み取り、許可リストと照合して検証し、一致したオリジンをそのまま返すことです。キャッシュがオリジンごとに別々のコピーを保存できるよう、レスポンスに Vary: Origin を加えてください。

検証を伴わないオリジンの反映。許可リストを確認せずに Origin リクエストヘッダーをそのまま返すと、API があらゆるドメインに開かれてしまいます。攻撃者は自分が管理するページを通じてデータを盗むためにこれを悪用します。反映する前に、必ず受信したオリジンを信頼できる値のリストと照合してください。

CDN が誤ったオリジンのレスポンスをキャッシュする。サーバーが動的なオリジンの値を返しているのに Vary: Origin を省略すると、CDN は最初のオリジンの値を保存し、以降のすべてのオリジンに同じキャッシュ済みレスポンスを配信します。動的なオリジンを反映するすべてのレスポンスに Vary: Origin を加えてください。Cloudflare では CORS のマネージドトランスフォームを使うとこれが自動的に処理されます。他の CDN では、オリジンがキャッシュキーの一部になっていることを確認してください。

プリフライトは成功するのに実際のリクエストが失敗する。OPTIONS のレスポンスには CORS ヘッダーが含まれているのに、その後の GET、POST、PUT のレスポンスには含まれていません。多くのサーバーフレームワークは OPTIONS を他のメソッドとは別に扱います。CORS ヘッダーがプリフライトのレスポンスだけでなく、すべての種類のレスポンスに付加されるようにしてください。Express では、すべてのレスポンスがミドルウェアを通るよう、CORS ミドルウェアをルートハンドラーより前に配置します。

curl では正しいヘッダーが見えるのにブラウザはなおブロックする。DevTools を開いて Network タブに移動し、ブラウザが実際に受け取ったレスポンスヘッダーを調べてください。プロキシ、ロードバランサー、CDN のエッジルールが、オリジンサーバーとブラウザの間で CORS ヘッダーを取り除いたり上書きしたりすることがあります。curl の出力と DevTools の出力を比較して、ヘッダーを削除している層を特定します。