>_devtools-hub
CORSHTTPセキュリティ

CORSの仕組みと設定 — プリフライトリクエストとAccess-Controlヘッダーを理解する

CORSエラーの原因・プリフライトリクエストの仕組み・サーバー側の正しい設定方法・よくある誤設定を解説します。「CORSエラーが出て困った」という経験を持つ開発者向けの実践ガイドです。

「ローカル環境でAPIを叩いたらCORSエラーになった」「フロントエンドとバックエンドのドメインが違うとエラーが出る」という経験は多くのフロントエンド開発者が持っています。CORSはセキュリティ上重要な仕組みですが、設定が複雑でエラーの原因がわかりにくいことも事実です。この記事では、CORSエラーの発生原因から、サーバー側の正しい設定方法、そして「とりあえず `*` にした」では解決しない問題まで、実務的な観点で解説します。

同一オリジンポリシーとCORSの関係

ブラウザには「同一オリジンポリシー(Same-Origin Policy)」というセキュリティ機能があり、スクリプトは自分と違うオリジン(スキーム+ホスト+ポートの組み合わせ)から返ってきた内容を読めません。`https://app.example.com` のJavaScriptから `https://api.example.com` にfetchすると、ホストが異なるため、応答を読むことがブロックされます。CORS(Cross-Origin Resource Sharing)は、サーバーが「このオリジンには読ませてよい」とブラウザに伝えるための仕組みです。ここで誤解されやすいのが、ブロックされるのは「応答を読むこと」であって、リクエストが送られないわけではない点です。CORSのヘッダーを一切返さないサーバーに別オリジンのページから送って確かめたところ、JavaScriptはどの応答も読めませんでしたが、GET と、フォームと同じ形式(application/x-www-form-urlencoded)のPOSTは、サーバーにそのまま届いていました。JSONのPOSTだけは、次の節のプリフライトで止まり、本体は送られませんでした。CORSはあくまでブラウザの制限なので、curlやPostmanはその影響を受けず、「curlでは動くのにブラウザで動かない」という状況はCORSが原因であることが多いです。

プリフライトリクエストとは何か

CORSの「プリフライトリクエスト」は、実際のリクエストを送る前にブラウザが自動的に送信するOPTIONSリクエストです。`PUT`・`DELETE`・`PATCH` メソッド、`Authorization` などのヘッダー付き、Content-Typeが `application/json` のPOSTなどはプリフライトが発生します。ブラウザは `Origin` と `Access-Control-Request-Method: POST` などを付けた OPTIONS を先に送り、サーバーが許可するヘッダーを返したときだけ本リクエストを送ります。サーバーで OPTIONS を処理していないとプリフライトが失敗し、「GETは動くのにPOSTで失敗する」という典型的な症状になります。サーバーがプリフライトに正しく応えているかは、ブラウザと同じ OPTIONS を自分で送ると確かめられます。HTTP Request Builder でメソッドを OPTIONS にし、ヘッダーに Origin と Access-Control-Request-Method を入れると、そのまま実行できる curl のコマンドが出てくるので、`-i` を付けて実行し、応答に Access-Control-Allow-Origin などが含まれているかを見ます。

この手順で使うツール

HTTP Request Builder

GUIでHTTPリクエストを組み立て curl / fetch / axios コードを即生成

正しいAccess-Controlヘッダーの設定

`Access-Control-Allow-Origin` は許可するオリジンを指定します。値に書けるのは1つのオリジンか `*` だけで、カンマで複数並べることはできません。複数のオリジンを許可したいときは、リクエストの Origin が許可リストに入っていればその値をそのまま返し、あわせて `Vary: Origin` を付けます。Vary が無いと、CDN やプロキシがあるオリジン向けの応答を別のオリジンにも使い回すことがあります。`*` は全オリジンを許可しますが、Cookieや認証情報を送るリクエスト(`credentials: "include"`)では使えません。`Access-Control-Allow-Methods` は許可するメソッド、`Access-Control-Allow-Headers` はリクエストで使えるヘッダー、`Access-Control-Max-Age` はプリフライトの結果をキャッシュしてよい秒数です。CORS Header Builder でオリジンやメソッドを選ぶと、ヘッダーのほか nginx・Express・Next.js の設定の形で出力でき、複数のオリジンを入れた場合は許可リストと Vary: Origin を使う形で出てきます。

この手順で使うツール

CORS Header Builder

CORSのAccess-ControlヘッダーをGUIで生成

よくある誤設定と、本当の危険

`Access-Control-Allow-Origin: *` と `Access-Control-Allow-Credentials: true` を同時に返しても、ブラウザは応答を読ませません。どこのサイトからでもログイン中の利用者の情報を読めてしまうのを防ぐための決まりです。本当に危ないのは、これを避けようとして「リクエストの Origin をそのまま Allow-Origin に返し、Credentials も true にする」設定です。こうすると、利用者が悪意のあるサイトを開いただけで、そのサイトのJavaScriptが利用者のCookieつきでAPIを呼び、応答の中身(個人情報など)を読み取れてしまいます。`Origin: null` を許可するのも同じく危険で、サンドボックス化したiframeなど、どこからでも null を名乗れます。一方、CSRF(利用者になりすましてリクエストを送らせる攻撃)は、最初の節で見たとおりCORSでは防げません。リクエスト自体は届いてしまうので、CSRFにはSameSite属性つきのCookieやCSRFトークンで別に備えます。正しい対応は、フロントエンドのオリジンだけを許可リストに入れることです。Next.jsなどのBFF(Backend for Frontend)を挟んで、フロントエンドとAPIを同じオリジンにすれば、CORSの設定そのものが不要になります。

この手順で使うツール

CORS Header Builder

CORSのAccess-ControlヘッダーをGUIで生成

まとめ

CORSは「セキュリティ上の制限」であり、バグではありません。正しい理解は「ブラウザが同一オリジンポリシーでアクセスをブロックしているのを、サーバー側のヘッダーで許可する」というものです。プリフライトリクエストへの対応・CredentialsとAllow-Originの組み合わせルール・本番での最小権限設定という3点を押さえることで、安全かつ正しいCORS設定が実装できます。

このツールで試す

HTTP Headers Reference

主要 HTTP ヘッダーの用途・構文・使用例をまとめたリファレンス

Web開発ネットワーク

使ってみる →

BOOTH

HTTP Request Builder

GUIでHTTPリクエストを組み立て curl / fetch / axios コードを即生成

HTTPAPI開発者向けWeb開発

使ってみる →

BOOTH

CORS Header Builder

CORSのAccess-ControlヘッダーをGUIで生成

開発者向けCORSHTTPセキュリティ

使ってみる →

関連ガイド