• 診断項目 No.30/127
  • CORS(クロスオリジン設定)
  • 重大度 重要(high)

CORSの認証情報設定に矛盾がないとは?Access-Control-Allow-Credentialsの正しい使い方・診断基準・設定例

CORSの認証情報設定に矛盾がないとは、Access-Control-Allow-Credentials: true を * や null と組み合わせていない状態です。危険な組み合わせ、Originの反射、Apache・nginx・Express・PHPの設定例を解説します。

結論(CORSの認証情報設定に矛盾がない)

CORSの認証情報設定に矛盾がないとは、Access-Control-Allow-Credentials: trueを、「*」や「null」オリジンと組み合わせていない状態です。この指定はCookieなどの認証情報を伴う外部サイトからの読み取りを許すもので、「*」は全オリジン、「null」は誰でも作り出せるオリジンを意味します。とくにnullとの組み合わせは、ログイン中の利用者の個人データを攻撃者のページから読み取れる実際に悪用可能な構成です。セキュリティAIチェッカーは、この組み合わせを × 要改善と判定します。

この記事のポイント

  • Access-Control-Allow-Credentials: true は「ログイン中の利用者の権限で取得したデータを外部に渡してよい」という強い許可です。
  • * + credentials はブラウザが拒否する仕様違反の設定で、反射方式への書き換えで本当に危険になりがちです。
  • null + credentials は、サンドボックス化iframeの null オリジンから実際に読み取れる悪用可能な構成です。
  • 診断はトップページで Allow-Origin がなければ対象外、* または null と Credentials: true の併用で ×(重み3)、それ以外は ○ です。
  • 対策は、固定の許可リストと完全一致したオリジンだけに値と Credentials: true を返し、Vary: Origin を付けることです。
  • Allow-Credentials: false は有効な値ではなく、不要ならヘッダー自体を出力しません。
診断項目名CORSの認証情報設定に矛盾がない
項目IDheaders.cors-credentials
分類CORS(クロスオリジン設定)
重大度・配点の重み重要(high) 重み 3
関連する標準・ガイドラインOWASP ASVS 5.0.0 V3.4.2(Access-Control-Allow-Originは固定値か許可リスト照合済みの値とする、L1)、OWASP WSTG-CLNT-07、WHATWG Fetch Standard(CORS check)、CWE-942、CWE-346(オリジン検証の誤り)

CORSの認証情報設定に矛盾がないとは(Access-Control-Allow-Credentialsの確認)

CORSの認証情報設定に矛盾がないとは、Access-Control-Allow-Credentials: true を、全オリジンを意味する * や、誰でも作り出せる null オリジンと組み合わせていない状態のことです。セキュリティAIチェッカーはこの項目(headers.cors-credentials)で、トップページの応答にこの危険な組み合わせがないかを確認します。

CORSでは、Cookieやログイン情報(認証情報、credentials)を伴うクロスオリジン要求の応答を外部サイトに読ませるかどうかを、Access-Control-Allow-Credentials: true ヘッダーで制御します。このヘッダーを返すということは、「ログイン中の利用者の権限で取得したデータを、許可したオリジンのJavaScriptに渡してよい」という強い許可を意味します。

そのため、認証情報の許可は、信頼できる具体的なオリジンだけと組み合わせなければなりません。

項目内容
項目IDheaders.cors-credentials
診断カテゴリAPI・通信設定
重大度high
重み3
関連標準OWASP ASVS 5.0.0 V3.4.2(L1)、OWASP WSTG-CLNT-07、WHATWG Fetch Standard(CORS check)、CWE-942、CWE-346
関連項目「危険なCORSワイルドカードがない」、「任意Originを反射しない」、「CORSプリフライトの許可範囲」

認証情報付きCORSの仕組み(Fetch StandardのCORS check)

WHATWG Fetch StandardのCORS checkでは、次の順で判定されます。

  1. Access-Control-Allow-Origin がなければ失敗。
  2. 認証情報なしの要求で値が * なら成功。
  3. 値が要求元オリジンのシリアライズ結果と一致しなければ失敗。
  4. 認証情報なしなら成功。
  5. 認証情報ありの場合、Access-Control-Allow-Credentials が true なら成功、それ以外は失敗。

MDNも、ワイルドカードと認証情報を併用しようとするとエラーになり、Access-Control-Allow-Credentials の有効な値は大文字小文字を区別する true のみで、不要な場合は false を送らずヘッダー自体を省略すべきだとしています。

CORSの認証情報設定で「矛盾」とされる2つの危険な組み合わせ

組み合わせブラウザの挙動意味
* + Credentials: true認証情報付きの要求では手順3で失敗し、応答は読めない仕様違反の設定。開発者が「認証付きで外部に開放したい」意図を持っている兆候で、他の経路(Originの反射)で同じ意図が実装されていることが多い
null + Credentials: trueサンドボックス化iframe等の null オリジン文書から読み取り可能実際に悪用可能。攻撃者のページからログイン中利用者の個人データを取得できる

null の組み合わせについては、WSTG-CLNT-07が、null オリジンを単純に反射し、特に認証情報を許可している場合、汎用ワイルドカードと同様の脆弱性になると説明し、サンドボックス化 iframe と credentials: 'include' を使った攻撃例を示しています。

具体的なオリジン+認証情報は問題ないのか

Access-Control-Allow-Origin: https://app.city.example.lg.jp と Credentials: true の組み合わせは、仕様どおりの正しい使い方です。

ただし、その値が「要求の Origin をそのまま返した結果」であれば、任意のサイトに認証情報付きの読み取りを許すことになり最も危険です。この「反射」は Origin を付けた要求を送らないと観測できないため、関連項目「任意Originを反射しない」(未許可Originを付けたGETで反射の有無を確認)で評価します。

認証情報付きCORSについてよくある誤解

  • 「* と credentials はブラウザが拒否するから無害」:その応答自体は読めませんが、設定意図の誤りを示します。修正の過程で * を「要求Originの反射」に置き換えてしまい、本当に悪用可能な状態になる事例が典型です。
  • 「Access-Control-Allow-Credentials: false を返せば安全」:false は有効な値ではありません。不要ならヘッダーを出力しないのが正しい設定です。

認証情報を伴わない * / null の許可そのものは「危険なCORSワイルドカードがない」で評価します。このページの項目は、認証情報の許可との組み合わせ(矛盾)に集中しています。

CORSの認証情報設定に矛盾がないの診断基準(セキュリティAIチェッカー)

取得対象

  • 入力URLへのGET(Origin ヘッダーは付けない、リダイレクト最大4回追跡)で得た最終ページの応答ヘッダー Access-Control-Allow-Origin と Access-Control-Allow-Credentials。
  • Access-Control-Allow-Credentials は、値が true(大文字小文字を区別しない)のとき「認証情報を許可」とみなします。仕様上は小文字の true のみが有効ですが、True 等の表記でも許可の意図があるものとして扱います。

判定条件

判定条件得点への影響
○ 問題なし(pass)Allow-Origin があり、下記の危険な組み合わせではない(認証情報の許可なし、または具体的オリジン+認証情報)重み3を満点で加算
× 要改善(fail)Allow-Credentials: true かつ Allow-Origin が * または null重み3が分母に入り得点0
対象外(na)トップページの応答に Access-Control-Allow-Origin がない分母から除外
  • Access-Control-Allow-Origin がない応答では、認証情報の設定が有効に働く余地がなく、「矛盾がない」と積極的に評価する材料もないため対象外とします。多くの自治体公式サイトのトップページはこの状態です。
  • 根拠欄には観測した Access-Control-Allow-Origin の値と、認証情報の許可有無を表示します。

自治体サイトでの判定例

状況判定
公式サイトのトップページにCORSヘッダーなし対象外
静的配信で Access-Control-Allow-Origin: * のみ(Credentialsなし)○(本項目は矛盾なし。「危険なCORSワイルドカードがない」で △)
フレームワークの設定で origin: '*' と credentials: true を同時指定×
開発時の名残で null と Credentials: true×

CORSの認証情報設定に矛盾があるとどんなリスクがあるか

  • ログイン中の個人データの窃取:null +認証情報、または反射+認証情報の構成では、利用者が攻撃者のページを開いただけで、そのページのJavaScriptが利用者のCookie付きで電子申請やマイページのAPIを呼び出し、氏名・住所・申請内容などを読み取って外部へ送信できます。
  • CSRFトークンの窃取:応答に含まれるCSRFトークンを読み取られると、CSRF対策が無効化され、なりすまし操作につながります。
  • 設定の連鎖的な誤り:* +認証情報の設定は、それ自体は読み取りを許さなくても、「動かない」ことを理由に反射方式へ書き換えられ、本当に危険な状態になりがちです。

認証情報付きCORSの正しい設定方法(Apache・nginx・Express・PHP)

基本方針

  1. 認証情報付きのクロスオリジン利用が本当に必要か確認する(同一オリジンで完結するなら、CORSヘッダー自体を出力しない)。
  2. 必要な場合は、許可オリジンを固定のリストで管理し、要求の Origin がリストと完全一致したときだけ、その値と Access-Control-Allow-Credentials: true を返す。
  3. *、null、部分一致(endsWith("example.lg.jp") 等)での許可を使わない。
  4. 応答が Origin によって変わるので Vary: Origin を付ける。

Apache(.htaccess)

<IfModule mod_headers.c>
  # まず誤った一括設定を除去(生成元により格納先が異なるため両方を指定)
  Header unset Access-Control-Allow-Origin
  Header always unset Access-Control-Allow-Origin
  Header unset Access-Control-Allow-Credentials
  Header always unset Access-Control-Allow-Credentials
  # 許可リストに一致したときだけ付与
  SetEnvIf Origin "^(https://app\.city\.example\.lg\.jp)$" CORS_ALLOW=$1
  Header always set Access-Control-Allow-Origin "%{CORS_ALLOW}e" env=CORS_ALLOW
  Header always set Access-Control-Allow-Credentials "true" env=CORS_ALLOW
  Header always merge Vary "Origin"
</IfModule>

nginx

# mapはhttpコンテキスト、locationはserverコンテキストに記述
map $http_origin $cors_allow {
    default "";
    "https://app.city.example.lg.jp" $http_origin;
}
map $cors_allow $cors_cred {
    default "true";
    "" "";
}
location /api/ {
    add_header Access-Control-Allow-Origin $cors_allow always;
    add_header Access-Control-Allow-Credentials $cors_cred always;
    add_header Vary Origin always;
}

値が空文字の add_header は出力されないため、許可リストに一致しない要求にはCORSヘッダーが付きません。location 内に add_header を書くと server レベルの add_header(他のセキュリティヘッダーを含む)は継承されないため、必要なヘッダーは同じ location にも記述してください。

Node.js(Express+cors)

const cors = require('cors');
const ALLOWED = ['https://app.city.example.lg.jp'];
app.use('/api', cors({
  origin: (origin, cb) => cb(null, ALLOWED.includes(origin) ? origin : false),
  credentials: true,
}));

origin: true(要求Originをそのまま反射)や origin: '*' と credentials: true の組み合わせは使わないでください。

PHP

<?php
$allowed = ['https://app.city.example.lg.jp'];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
header('Vary: Origin');
if (in_array($origin, $allowed, true)) {
    header('Access-Control-Allow-Origin: ' . $origin);
    header('Access-Control-Allow-Credentials: true');
}

確認方法(curl)

curl -sI https://www.city.example.lg.jp/ | grep -i '^access-control-allow-'
curl -sI -H 'Origin: null' https://www.city.example.lg.jp/api/me | grep -i '^access-control-allow-'
curl -sI -H 'Origin: https://evil.example' https://www.city.example.lg.jp/api/me | grep -i '^access-control-allow-'

2行目・3行目で null や https://evil.example と Access-Control-Allow-Credentials: true が同時に返る場合は、直ちに修正が必要です。修正後はセキュリティAIチェッカーで再診断します。

サイトを壊さないための注意点(ガードレール)

  • 認証情報の許可を外すと、別オリジンの業務画面(例:申請フロントとAPIが別ドメイン)が動かなくなる場合があります。利用中のフロントエンドのオリジンを洗い出し、許可リストに登録してから不要な設定を外してください。
  • CookieにSameSite属性(Lax/Strict)を設定すると、クロスサイトの認証情報付き要求自体が送られにくくなり、CORS設定の誤りに対する多層防御になります。

よくある質問(FAQ)

Access-Control-Allow-Origin: * と Access-Control-Allow-Credentials: true は併用できますか?

できません。Fetch StandardのCORS checkでは、認証情報付きの要求は値が要求元オリジンと一致しなければ失敗するため、ブラウザは応答を読ませません。MDNも、ワイルドカードと認証情報を併用しようとするとエラーになるとしています。

* + credentials はブラウザが拒否するなら無害ではないのですか?

その応答自体は読めませんが、「認証付きで外部に開放したい」という設定意図の誤りを示します。動かないことを理由に * を要求Originの反射に置き換え、本当に悪用可能な状態になる事例が典型です。

Access-Control-Allow-Origin: null と credentials の組み合わせはなぜ危険ですか?

攻撃者はサンドボックス化したiframeで自分のページを null オリジンにできるため、利用者が攻撃者のページを開いただけで、Cookie付きでマイページなどのAPIを呼び出し個人データを読み取れます。WSTG-CLNT-07もこの攻撃例を示しています。

Access-Control-Allow-Credentials: false を返せば安全ですか?

false は有効な値ではありません。有効な値は大文字小文字を区別する true のみで、不要な場合はヘッダー自体を出力しないのが正しい設定です。

トップページにCORSヘッダーがない場合、CORSの認証情報設定の項目はどう判定されますか?

対象外(na)になり、得点の分母から除外されます。Access-Control-Allow-Originがない応答では認証情報の設定が働く余地がないためで、多くの自治体公式サイトのトップページはこの状態です。

具体的なオリジンと credentials: true の組み合わせなら安全ですか?

仕様どおりの正しい使い方で、この項目は ○ です。ただし、その値が要求のOriginをそのまま返した結果なら、任意のサイトに認証付きの読み取りを許す最も危険な状態です。反射は「任意Originを反射しない」の項目で確認します。

認証情報の許可を外すと業務システムが止まりませんか?

申請フロントとAPIが別ドメインの場合など、別オリジンの業務画面が動かなくなることがあります。利用中のフロントエンドのオリジンを洗い出して許可リストに登録してから、不要な設定を外してください。

セキュリティAIチェッカーを利用する

この項目を含む127項目を、URLを入れるだけで無料診断します。

参考資料