CORSとは
CORS(Cross-Origin Resource Sharing)は、あるオリジン(スキーム、ホスト、ポートの組)のページから、別のオリジンのサーバーに送ったリクエストの応答を、JavaScriptが読んでよいかを、サーバーが許可する仕組みです。ブラウザの同一オリジンポリシーに対する、サーバー側からの例外の宣言にあたります。
CORSの設定が重要な理由
許可が緩すぎると、悪意のあるサイトを開いた利用者のブラウザを通じて、その利用者がログインしているサイトのAPIの応答を読み取られます。典型的な誤りは、リクエストの Origin をそのまま Access-Control-Allow-Origin に返し、Access-Control-Allow-Credentials: true を付ける設定です。
反対に、許可が足りないと、自社のフロントエンドからAPIを呼べず、画面が動きません。
CORSの仕組み
- ブラウザが、リクエストに
Originヘッダーを付けて送る。 - サーバーが、応答の
Access-Control-Allow-Originで、読んでよいオリジンを返す。 - ブラウザが一致を確かめ、一致したときだけ、JavaScriptに応答を渡す。
| ヘッダー | 役割 |
|---|---|
Access-Control-Allow-Origin | 読み取りを許可するオリジン。* は誰でも |
Access-Control-Allow-Credentials | Cookieなどの認証情報つきのリクエストを許可する |
Access-Control-Allow-Methods、-Headers | 事前確認(OPTIONS)で、使えるメソッドとヘッダーを返す |
Vary: Origin | 応答がOriginで変わることを、キャッシュに知らせる |
CORSは、リクエストがサーバーに届くこと自体は止めません。ブラウザが、応答をJavaScriptに渡さないだけです。認証や認可の代わりにはなりません。
CORSの確認方法
自分のAPIに、見知らぬオリジンを名乗ってリクエストを送り、反射されないかを確かめます。自分で管理するサイトにだけ行います。
curl -s -D - -o /dev/null -H 'Origin: https://evil.example' https://example.com/api/ | grep -i '^access-control'
curl -s -D - -o /dev/null -H 'Origin: null' https://example.com/api/ | grep -i '^access-control'
https://evil.example や null が Access-Control-Allow-Origin に返り、Access-Control-Allow-Credentials: true も付いていれば、危険な状態です。
CORSの設定例
許可するオリジンを、一覧(許可リスト)で決め、一致したものだけを返します。
nginxの例です。
map $http_origin $cors_origin {
default "";
"https://app.example.com" $http_origin;
"https://admin.example.com" $http_origin;
}
server {
location /api/ {
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Vary Origin always;
}
}
Apache(mod_headersとmod_setenvif)の例です。
SetEnvIf Origin "^https://(app|admin).example.com$" CORS_ORIGIN=$0
Header always set Access-Control-Allow-Origin "%{CORS_ORIGIN}e" env=CORS_ORIGIN
Header always merge Vary Origin
WordPressのREST APIでは、本体が返すCORSヘッダーを外し、許可リストに置き換えます。
add_action('rest_api_init', function () {
remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
add_filter('rest_pre_serve_request', function ($value) {
$allowed = array('https://app.example.com');
$origin = get_http_origin();
if ($origin && in_array($origin, $allowed, true)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Vary: Origin', false);
}
return $value;
});
}, 15);
よくある間違いと注意点
*と認証情報つきのリクエストは併用できません。ブラウザが応答を拒否します。認証が不要な公開データだけに*を使います。- 許可の判定を「
example.comを含むか」のような部分一致にすると、example.com.evil.testのような別のドメインも通ります。完全一致で比べます。 Origin: nullを許可しない。ファイルやサンドボックス化されたiframeからのリクエストが、nullを名乗ります。- Originごとに応答を変えるときは
Vary: Originを付けます。付けないと、CDNやキャッシュが別のオリジン向けの応答を返すことがあります。
Webサイト セキュリティチェッカーで確認する
Webサイト セキュリティチェッカーは、任意のOriginを反射して認証情報も許可する設定や、null を許可する設定を、1回のリクエストで診断します。公開APIの意図的な設定は、重大度を下げて示します。
関連用語
- セキュリティヘッダー
- CSP
- XSS(クロスサイトスクリプティング)
- HttpOnly属性
関連する用語
サイトの設定を無料で確認する
サイトのURLを入力するだけで、CORS などの設定状況を診断できます。Webサイト セキュリティチェッカー「Security Checker X」は、登録なしで使えます。









