MENU

CORS設定ミスとは?クロスオリジンリソース共有の脆弱性・悪用手口・対策を現場目線で解説

「APIサーバーには認証も付けているし、HTTPSにもしている。それで十分では?」

そう考えている現場は少なくありません。しかし、CORS(Cross-Origin Resource Sharing)の設定を一つ間違えるだけで、ブラウザの同一オリジンポリシーという強力な防壁をまるごと無効化できてしまいます。

この記事では、CORS設定ミスがどのように悪用されるか、そして開発者・情シス担当者が今すぐ確認すべき設定のポイントを、現場の視点で解説します。OWASPがAPIセキュリティの重要課題として繰り返し取り上げているテーマですが、「よくわからないまま `*` を設定してしまった」という環境は国内でも相当数存在します。

TOC

CORSとは?そして「同一オリジンポリシー」との関係

まずCORSを理解するには、ブラウザが標準で持つ「同一オリジンポリシー(Same-Origin Policy)」を知る必要があります。

同一オリジンポリシーとは、「あるオリジン(スキーム+ホスト+ポートの組み合わせ)から読み込まれたスクリプトは、別のオリジンのリソースには原則アクセスできない」というブラウザのセキュリティ機能です。

たとえば `https://www.example.com` にある JavaScript は、同じポリシーにより `https://api.example.com` や `https://other-site.com` へ直接リクエストを送って応答を読み取ることができません。これがXSS攻撃の被害を一定範囲に抑える基盤になっています。

しかし現代のWebアプリケーションでは、フロントエンド(`https://app.example.com`)がバックエンドAPI(`https://api.example.com`)を呼び出すアーキテクチャが当たり前になっています。これはオリジンが異なる通信です。このような正規のクロスオリジン通信を許可する仕組みが CORS です。

サーバーはHTTPレスポンスヘッダーに `Access-Control-Allow-Origin` などのCORSヘッダーを付与することで、「このオリジンからのリクエストを許可する」とブラウザに伝えます。問題は、この「許可」の設定が甘いと、攻撃者が悪意のある第三者サイトから正規サーバーのAPIを呼び出し、ログイン済みユーザーのデータを盗み出せてしまう点にあります。

CORS設定ミスの仕組み(攻撃者視点で理解する)

1. ワイルドカード設定(`Access-Control-Allow-Origin: *`)の誤用

最も単純な設定ミスは、全オリジンを許可するワイルドカード `*` の誤用です。

何が起きるか: あらゆるサイトから当該APIへのクロスオリジンリクエストが許可されます
ただし制限あり: `*` を設定したAPIは `Access-Control-Allow-Credentials: true` と組み合わせることができません(ブラウザが拒否します)
問題が残るケース: 認証不要の公開APIであっても、センシティブな情報(利用統計・内部ロジックの推測材料等)を返している場合は注意が必要です

2. Originヘッダーのオウム返し(リクエストヘッダー値をそのまま返却)

より深刻な設定ミスは、サーバーがリクエストの `Origin` ヘッダーの値を検証せずにそのまま `Access-Control-Allow-Origin` に返却するパターンです。

# 脆弱な実装の例(Nginxの設定ファイルより) # リクエストのOriginヘッダーをそのまま返している add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Credentials true;

この設定は一見「柔軟で便利」に見えますが、攻撃者が制御する `https://evil-attacker.example` というサイトからリクエストを送れば、そのオリジンが許可されてしまいます。さらに `Credentials: true` を組み合わせると、ブラウザはクッキーや認証トークンを自動的に送信します。つまり、ログイン済みのユーザーが攻撃者のページを訪問した瞬間に、そのユーザーの認証情報でAPIが呼び出されるという事態になります。

3. ホワイトリスト検証の不備(前方一致・後方一致の誤り)

「信頼するオリジンのリストだけを許可する」というアプローチ自体は正しいのですが、正規表現の扱いを誤ると穴ができます。

後方一致の誤用: `example.com` で終わるオリジンを全許可すると、`evil-example.com` や `attackerexample.com` も許可対象になります
サブドメインの過剰許可: `*.example.com` を許可する場合、`example.com` 傘下の全サブドメインが信頼の範囲に入ります。万一古いサブドメインが乗っ取られると(サブドメインテイクオーバー)、そこが攻撃の足場になります
httpとhttpsの混在: `http://trusted.example.com` を許可リストに入れていると、HTTPSではなくHTTPで通信した場合に中間者攻撃のリスクが高まります

4. preflight(OPTIONS)のバイパス

CORSには「単純リクエスト」と「preflight(プリフライト)が必要なリクエスト」の区別があります。

GETやPOSTでContent-Typeが `application/x-www-form-urlencoded` 等の場合は単純リクエストとして扱われ、preflightが省略されます。サーバー側でpreflightの扱いを誤ると、本来制限すべきリクエストが通過してしまうことがあります。

攻撃シナリオ:実際に何が盗まれるか

ここでは防御のために、攻撃者がどのような流れでデータを窃取するかを整理します。

シナリオ: 社内Webアプリのユーザー情報漏洩

1. 攻撃者が `https://malicious-site.example` というページを用意する
2. このページにはJavaScriptが仕込まれており、被害者が訪問すると自動的に `https://internal-app.company.example/api/user/profile` へリクエストが送られる
3. 内部APIのCORSが「Originヘッダーをそのまま返す」設定になっている場合、ブラウザはリクエストを通過させる
4. ユーザーがその社内アプリにログイン中であれば、セッションクッキーが自動添付されてAPIが呼ばれる
5. レスポンスが悪意のあるサイトのJavaScriptに渡り、氏名・メールアドレス・権限情報等が外部に送信される

このシナリオはCSRFと似ていますが、CSRF対策のトークンが設定されていてもCORSが壊れていればレスポンスの読み取りまで可能という点が異なります。CSRFは「リクエストを送れる」攻撃、CORS設定ミスは「レスポンスも読める」攻撃です。

具体的な修正・防御手順

1. 許可するオリジンの明示的なホワイトリスト化

`*` やオウム返しを止め、信頼するオリジンを正確に列挙します。複数のオリジンを許可する場合は、サーバー側でリストと照合するロジックを実装してください。

# 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; add_header Access-Control-Allow-Credentials true; add_header Vary Origin; # ... } }

ポイントは以下の3点です。

完全一致で照合: 前方一致・後方一致では不十分、文字列全体を照合する
`Vary: Origin` ヘッダーを付与: プロキシ・CDNがオリジンごとにレスポンスをキャッシュするよう指示する(これを忘れると意図しないオリジンにキャッシュが返る場合がある)
HTTPSのみ許可: `http://` から始まるオリジンは許可リストに含めない

2. 認証APIには `credentials` の扱いを厳密にする

認証情報(クッキー・Authorizationヘッダー等)が関係するAPIでは、以下を必ずセットで確認します。

# 認証ありAPIのCORSヘッダー確認ポイント Access-Control-Allow-Origin: https://app.example.com # ワイルドカード禁止 Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization Vary: Origin

`Access-Control-Allow-Credentials: true` を設定する場合、`Access-Control-Allow-Origin` に `*` を指定するとブラウザがエラーを返します。認証を必要とするAPIには必ず具体的なオリジンを指定してください。

3. preflight(OPTIONSメソッド)の適切な処理

サーバーが `OPTIONS` メソッドのリクエストに対してCORSヘッダーを正しく返すよう設定します。

# Nginxでのpreflight対応例 if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin $cors_origin; add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS'; add_header Access-Control-Allow-Headers 'Authorization, Content-Type'; add_header Access-Control-Max-Age 86400; return 204; }

`Access-Control-Max-Age` を設定することでpreflightのキャッシュ時間を制御できます。長すぎる値(1週間以上)は設定変更が反映されにくくなるため、1日(86400秒)程度が実用的です。

4. APIフレームワークのCORS設定を確認する

Expressなど一般的なフレームワークには `cors` ミドルウェアが存在します。デフォルト設定のままにしていないか確認します。

// Node.js + Express での安全なCORS設定例 const cors = require('cors'); const allowedOrigins = [ 'https://app.example.com', 'https://admin.example.com' ]; app.use(cors({ origin: function(origin, callback) { // originがundefined(curlなど直接リクエスト)の場合は拒否 if (!origin) return callback(new Error('No origin')); if (allowedOrigins.includes(origin)) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } }, credentials: true }));

`origin: true` という設定は「Originをそのまま返す」動作になるため、要注意です。ホワイトリストと照合する関数を必ず渡してください。

中小企業でも今日からできること

CORS設定は「アプリケーション側の問題」として見過ごされがちですが、情シス担当者が外部委託先や自社開発チームに確認・要求できる事項があります。

既存システムのCORSヘッダー確認: ブラウザの開発者ツール(F12)→ Networkタブ → APIのレスポンスヘッダーを確認し、`Access-Control-Allow-Origin: *` や `Access-Control-Allow-Credentials: true` との組み合わせがないかチェックする
開発委託契約にCORSセキュリティ要件を明記: 「認証APIのCORSホワイトリストを提出すること」「ワイルドカード禁止」をシステム開発要件に入れる
定期的な脆弱性スキャン: OWASP ZAP(無料)などのツールはCORS設定ミスを自動検出する機能を持っています。社内テスト環境に対して定期実行することを検討してください
開発環境のCORS設定を本番に流用しない: 開発時は `*` で楽に動かし、そのまま本番にデプロイするケースが事故の温床です。環境ごとの設定差異を管理する仕組みを整えることが重要です

姉妹サイトLinuxMaster.JPでは、Nginxのセキュリティ設定や、Webサーバーの安全なヘッダー管理についても詳しく解説しています。インフラ側でのCORS制御を検討している方はあわせてご覧ください。

よくある誤解と注意点

【誤解1】CORSはサーバー側のセキュリティ機能だ

CORS制御はあくまでもブラウザが行うものです。`curl` コマンドやサーバー間通信ではCORSヘッダーは無視されます。CORSで守られているのは「ブラウザを経由した攻撃」からであり、APIキーが漏洩した場合やサーバー間通信は別の対策が必要です。

【誤解2】CORSを設定すれば認証は不要だ

CORSはアクセス制御の「入り口」を絞るものですが、認証・認可の代替にはなりません。許可したオリジンであっても、その先でリクエストを送ってくるユーザーが正規ユーザーかどうかは別途確認が必要です。CORSと認証は並立して実装します。

【誤解3】プリフライトがあればCORSは安全だ

プリフライトはブラウザが「このリクエストを送ってよいか」を事前確認する仕組みであり、サーバーの設定が甘ければ通過させてしまいます。プリフライトはブラウザの保護機能の一部であって、万能の防壁ではありません。

【注意】`null` オリジンの扱い

`Access-Control-Allow-Origin: null` という設定は脆弱です。一部のブラウザ実装では、ローカルHTMLファイル・リダイレクト後のリクエスト・sandboxed iframeなどが `Origin: null` を送ることがあり、この設定により意図せず攻撃者に悪用される可能性があります。`null` を許可リストに含めないよう注意してください。

CORS設定チェックリストと脅威の整理

確認ポイント 安全な設定 リスクレベル
Access-Control-Allow-Origin 具体的なオリジンをホワイトリストで指定 高(ワイルドカード禁止)
Credentials+Originの組み合わせ Credentials:trueとワイルドカードを同時使用しない 高(認証情報漏洩リスク)
Originのオウム返し ホワイトリストと照合してから返却する 高(全オリジン許可と同等)
Vary: Origin ヘッダー 必ず付与する 中(CDN経由のキャッシュ汚染防止)
OPTIONSメソッド処理 preflightレスポンスを正しく返す 中(preflightバイパス防止)
null オリジンの許可 許可リストから除外する 中(ローカルhtml等の悪用防止)
HTTP(非HTTPS)オリジン HTTPSのオリジンのみ許可 低~中(MITM攻撃の経路排除)
開発環境設定の本番流用 環境変数で設定を分離する 高(設定漏れ事故の予防)

本記事のまとめ

CORS設定ミスは「地味に見えて実際の被害は深刻」という典型的なWebアプリケーション脆弱性です。以下の点を押さえておきましょう。

同一オリジンポリシーはブラウザの防壁: CORSはその防壁に「例外」を設ける仕組みであり、設定ミスは防壁を崩すことになる
ワイルドカードと`credentials:true`の組み合わせは論外: ブラウザが弾く仕様だが、Originのオウム返しでも同等のリスクが発生する
修正の基本はホワイトリスト+完全一致照合: 前後一致の正規表現を使う場合は特に慎重に設計する
`Vary: Origin` の付与を忘れない: CDNやリバースプロキシが誤ったキャッシュを返す事故を防ぐ
CORSはブラウザ経由の攻撃のみ防ぐ: 認証・認可・APIキー管理と並立して運用する

開発を外部委託している中小企業の情シス担当者も、ブラウザの開発者ツールでレスポンスヘッダーを確認するだけで異常を発見できます。まずは自社の主要WebシステムのCORSヘッダーを確認することから始めてみてください。

Webアプリのセキュリティ設定、本当に大丈夫ですか?

CORS以外にも、WebアプリケーションにはOWASP Top 10に挙げられる多くの設定ミス・実装ミスが潜んでいます。
正しいセキュリティ知識を体系的に身につけたい方へ、メルマガで実践的なセキュリティ対策ノウハウをお届けしています。

Let's share this post !

Author of this article

TOC