結論(CSPの過剰なワイルドカード)
CSPの過剰なワイルドカードとは、Content Security Policyの配信元リストに *(全オリジン)や https:(HTTPSならどこでも)などを書き、そのディレクティブが事実上何も制限しなくなっている状態です。特にスクリプトの配信元が広すぎると、攻撃者が自分で用意したHTTPSサイトや共有CDN上のスクリプトを読み込ませることができ、CSPの価値が失われます。*.example.lg.jp のような自組織のサブドメインに限ったワイルドカードは対象外です。
この記事のポイント
- * はHTTP/HTTPS(または保護対象ページと同じスキーム)のあらゆるURLに一致し、https://* も全HTTPSホストを意味します。
- スクリプトに https:・http:・data: を許すことも、全許可に近い危険な設定です。data: は任意コードの実行に使えます。
- script-src に 'strict-dynamic' がある場合、対応ブラウザはホスト・スキーム許可を無視するため、strict CSPの https: 併記は問題にしません。
- img-src * や connect-src * は、XSS発生時の情報流出の経路になります。
- セキュリティAIチェッカーは全オリジン許可またはスクリプトへのスキーム全体許可があれば△、なければ○と判定します。
| 診断項目名 | CSPの過剰なワイルドカード |
|---|---|
| 項目ID | headers.csp-wildcard |
| 分類 | コンテンツセキュリティポリシー(CSP) |
| 重大度・配点の重み | 重要(high) 重み 3 |
| 関連する標準・ガイドライン | OWASP ASVS 5.0.0 V3.4.3(L2:許可リストまたはnonce/hashの定義)、OWASP WSTG-CONF-12(ワイルドカード配信元の評価)、W3C CSP Level 3 §6.7.2.8・§8.6、CWE-79(多層防御として) |
CSPの過剰なワイルドカードとは
CSPの過剰なワイルドカードとは、Content Security Policy(CSP)の配信元リストに *(全オリジン)や https:(HTTPSならどこでも)などを書いた結果、そのディレクティブが事実上何も制限しなくなっている状態のことです。
# 危険:スクリプトをどこからでも読み込める
Content-Security-Policy: default-src * 'unsafe-inline' 'unsafe-eval'
特にスクリプトの配信元が広すぎると、攻撃者が自分で用意したHTTPSサイトや、誰でもファイルを置ける共有CDN上のスクリプトを読み込ませることができ、CSPを入れている意味が失われます。
セキュリティAIチェッカーのこの項目は、次の2種類を検出します。
- 全オリジンを許可するワイルドカード(
*、https://*など) - スクリプトに対するスキーム全体の許可(
https:、http:、data:)
*.example.lg.jp のようなサブドメインに限ったワイルドカードは、範囲が自組織に限られるため対象外です。
なぜCSPのワイルドカードは危険なのか(仕組み)
* が許すもの
W3C CSP3 のURL照合アルゴリズムでは、ソース式 * は「URLのスキームがHTTP(S)」または「保護対象ページと同じスキーム」であれば一致します。つまり script-src * は、インターネット上のあらゆるHTTP/HTTPSサーバーからのスクリプトを許可します。data:・blob: などは、明示しない限り含まれません。https://* も同様に、全HTTPSホストを意味します。
スキームだけのソース(https: / http: / data:)
https: のようにスキームだけを書いたソース式は、そのスキームの全URLに一致します。
Mozilla HTTP Observatory の実装は、script-src/object-src における *、http:、https:、ftp:、https://* などを「過度に広い配信元」とし、data: をスクリプトに許可することも 'unsafe-inline' と同等の危険として扱っています。data: を許すと、<script src="data:text/javascript,..."> という形で任意のコードを実行できるためです。
'strict-dynamic' との関係
script-src に 'strict-dynamic' がある場合、対応ブラウザは、そのリスト内のホスト許可・スキーム許可・'self'・'unsafe-inline' を無視し、nonce/hashで信頼したスクリプトだけを起点にします。Google推奨のstrict CSPでは、非対応ブラウザ向けのフォールバックとして https: を併記する書き方が使われるため、この場合の https: は問題としません。
ディレクティブごとのワイルドカードの影響
| ディレクティブ | ワイルドカードの影響 |
|---|---|
script-src/default-src | 任意の外部スクリプトの読込でXSS対策が無効になる |
object-src | プラグインコンテンツの読込('none' 推奨) |
frame-ancestors | どのサイトからでも埋め込み可能(クリックジャッキング) |
connect-src/img-src | XSS発生時に任意のサーバーへ情報を送信可能(CSP3の情報流出の節で例示) |
frame-src | 任意のサイトをiframeで表示可能 |
CSPのワイルドカードについてよくある誤解
- 「
https:だから安全」:HTTPSは通信の暗号化を保証するだけで、配信元が信頼できることは保証しません。攻撃者も、無料で証明書付きのサイトを用意できます。 - 「
img-src *は画像だけだから問題ない」:XSSが起きた際、画像リクエストのURLにデータを載せて外部へ送る手口に使われます。業務上必要なら把握した上で許可し、可能な範囲で絞り込みます。
平文HTTPの配信元そのもの(http://… や http:)は「CSPでHTTP配信元を許可していない」、default-src の有無は「CSPのdefault-src」でも評価します。
CSPの過剰なワイルドカードの診断基準(セキュリティAIチェッカー)
取得対象
- トップページの最終応答の
Content-Security-Policyヘッダー(カンマ区切りの複数ポリシーを個別に分解)と、HTML内のmeta CSPを対象にします。 - 各ポリシーを
;で分割し、トークンを小文字化して評価します。
検出条件
- 全オリジン許可のワイルドカード:任意のディレクティブの値に、
*、https://*、http://*、*:*のように、ホスト部全体が*のソース式がある。ただし、'strict-dynamic'を含むscript-src系のディレクティブは、ホスト許可が無視されるため除外します。 - スクリプトへのスキーム全体の許可:有効なスクリプト用リスト(
script-src、なければdefault-src)にhttps:、http:、data:がある。ただし、同じリストに'strict-dynamic'がある場合は除外します。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| △ 要確認(warn) | 上記1または2に該当(根拠欄に該当するディレクティブ名・スキームを表示) | 3×0.45=1.35点 |
| ○ 問題なし(pass) | どちらにも該当しない | 3点 |
| 対象外(na) | CSPがヘッダーにもmetaにもない | 採点に計上しない |
*.example.lg.jp のようなサブドメインのワイルドカード、https://cdn.example.com のような具体的なオリジンは対象外です。http: の配信元そのものは「CSPでHTTP配信元を許可していない」でも評価します。
自治体サイトでの判定例
| CSP | 判定 | 根拠 |
|---|---|---|
default-src * 'unsafe-inline' 'unsafe-eval' | △ | default-srcに * |
default-src 'self'; script-src 'self' https: | △ | スクリプトに https: |
default-src 'self'; img-src * | △ | img-srcに * |
frame-ancestors * | △(「クリックジャッキング対策」は×) | frame-ancestorsに * |
script-src 'nonce-abc' 'strict-dynamic' https: 'unsafe-inline' | ○ | strict-dynamicで無視される |
script-src 'self' *.city.example.lg.jp | ○ | 自組織に限定 |
frame-ancestors * の埋め込み許可は、「クリックジャッキング対策」で×として扱われます。
CSPのワイルドカードが過剰だとどんなリスクがあるか
- CSPバイパス:
script-srcにhttps:や*があると、XSSの注入点で<script src="https://攻撃者のサイト/x.js">を読み込ませるだけで、任意のコードが実行できます。CSPを入れているのに、実質無防備という状態です。 - 公開CDN経由のバイパス:広い許可に、誰でもファイルを置ける公開CDNが含まれると、そこに置かれた古いライブラリを悪用される手口が知られています。
- 情報流出:
connect-src *、img-src *は、XSS時に入力内容や画面情報を任意の外部サーバーへ送る経路になります。 - クリックジャッキング:
frame-ancestors *は、X-Frame-Optionsを無効化したうえで、どのサイトからの埋め込みも許します。
CSPのワイルドカードを絞り込む方法(Apache・nginx・IIS・Next.js)
修正の手順
- 実際の配信元を把握:ブラウザの開発者ツール(ネットワーク)やReport-Onlyの違反レポートで、各種類のリソースの配信元ドメインを一覧にします。
- 具体的なオリジンへ置き換え:
*やhttps:を、https://www.googletagmanager.com、https://maps.googleapis.comなど、実際に必要なオリジンへ置き換えます。 - スクリプトはnonce方式を検討:外部タグが多く許可リストが長くなる場合は、
'nonce-…' 'strict-dynamic'によるstrict CSPに移行すると、ホスト許可リストに頼らずに済みます。 - Report-Onlyで確認してから強制します。
Apache(.htaccess)
<IfModule mod_headers.c>
# 変更前: default-src * 'unsafe-inline'
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: https://www.google-analytics.com; connect-src 'self' https://www.google-analytics.com; frame-src https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
</IfModule>
nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;
IIS
<add name="Content-Security-Policy" value="default-src 'self'; script-src 'self' https://www.googletagmanager.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" />
Next.js(Vercel)
公式ガイドの第三者スクリプトの例のように、必要なドメインだけを追加します。
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic' https://www.googletagmanager.com;
connect-src 'self' https://www.google-analytics.com;
img-src 'self' data: https://www.google-analytics.com;
`;
サイトを壊さないための注意点
- 外部の地図・動画・SNS埋め込み・翻訳ツール・アクセシビリティ支援ツールは、複数のドメインからリソースを読み込みます。各サービスの公式ドキュメントで、CSPに必要なドメインを確認してください。
- サブドメインのワイルドカード(
*.example.com)は、そのドメイン配下に第三者がコンテンツを置ける場合(共有ホスティング、ユーザー投稿領域)は、実質的に広すぎる許可になります。 img-srcのdata:は一般的ですが、script-srcやobject-srcにはdata:を入れないでください。
設定後の確認方法
curl -sI https://www.example.lg.jp/ | grep -i '^content-security-policy' | tr -d '\r' | tr ';,' '\n\n' | grep -E "(^| )(\*|\*:\*|https?://\*|https?:|data:)( |$)"
tr -d '\r' は、ヘッダー行末の改行コード(CR)を取り除き、最後のディレクティブも検出できるようにするためです。表示された行が、全オリジン許可やスキーム全体の許可を含むディレクティブです。img-src の data: のように業務上許容しているものと、スクリプトへの許可を区別して確認してください。設定を変えたら、セキュリティAIチェッカーで再診断し、根拠欄にワイルドカードが表示されなくなったことを確認します。
よくある質問(FAQ)
CSPで script-src https: と書くのは安全ではないのですか?
安全ではありません。HTTPSは通信の暗号化を保証するだけで、配信元が信頼できることは保証しません。攻撃者も証明書付きのサイトを無料で用意できるため、XSSの注入点で攻撃者のサイトのスクリプトを読み込ませられます。
img-src * は画像だけなので問題ないのでは?
XSSが起きた際、画像リクエストのURLにデータを載せて外部へ送る手口に使われます。業務上必要なら把握した上で許可し、可能な範囲で具体的な配信元に絞り込みます。
*.example.lg.jp のようなサブドメインのワイルドカードも検出されますか?
検出しません。範囲が自組織に限られるためです。ただし、その配下に第三者がコンテンツを置ける場合(共有ホスティング、ユーザー投稿領域)は実質的に広すぎる許可になる点に注意してください。
strict CSPで https: を併記しているのに△になりませんか?
なりません。script-src に 'strict-dynamic' がある場合、対応ブラウザはホスト許可・スキーム許可を無視し、nonce/hashで信頼したスクリプトだけを起点にします。非対応ブラウザ向けの https: 併記は問題にしません。
script-src に data: を許可すると何が問題ですか?
script 要素の src に data:text/javascript,... を指定する形で任意のコードを実行できるためです。Mozilla HTTP Observatory の実装も、スクリプトへの data: 許可を 'unsafe-inline' と同等の危険として扱っています。
外部タグが多くて許可リストが長くなる場合はどうすればよいですか?
'nonce-…' と 'strict-dynamic' を使うstrict CSPに移行すると、ホスト許可リストに頼らずに済みます。外部の地図や動画などが必要とするドメインは、各サービスの公式ドキュメントで確認してください。
この項目を含む127項目を、URLを入れるだけで無料診断します。