見えるセキュリティ

Content Security Policy(CSP)

CONTENT SECURITY POLICY

この概念とは?

Content Security Policy(CSP)は、ページで読み込むものや実行するコードに制限を加える仕組みです。サイトが伝えた方針を、閲覧しているブラウザが適用します。この教材では、HTMLに混入したスクリプトの実行を、CSPで止める流れを見ます。

同じHTMLでも、ブラウザが適用する方針によって実行結果が変わります。

THEME
web-vuln
KIND
defense
REVIEW
self-reviewed ·

サイトの応答 → ブラウザの判断 → ページ表示

同じHTMLに含まれる2つのインラインscriptを、記載順に処理する例です。

この例では、入力の扱いに不備があり、HTMLにスクリプトが混入しています。HTMLは両モードで同じです。CSPありでは、nonce(その応答で許可するスクリプトに付ける値)を使って実行を制限します。

nonceは説明用の固定値です。実際は応答ごとに予測困難な値を生成します。

ページを配信するサイト

閲覧しているブラウザ

サイトが送るHTMLと応答ヘッダー

この例ではCSPの設定なし

サイトが用意したscript

scriptのnonce属性

r4V1mQ8pL2sN6dK0xC9bHw==

実行された場合の表示

「ようこそ」

混入したscript

scriptのnonce属性:なし

実行された場合の表示

「表示を書き換えました」

同じHTMLを見る
<p id="message">お知らせ</p>

<script nonce="r4V1mQ8pL2sN6dK0xC9bHw==">
  document.getElementById("message").textContent = "ようこそ";
</script>

<!-- 入力の扱いに不備があり、次のscriptが混入した前提 -->
<script>
  document.getElementById("message").textContent = "表示を書き換えました";
</script>

HTMLには正規scriptと混入scriptの両方があります。正規scriptのnonce属性はCSPなし側にもあります。

STEP 1 · 閲覧側ブラウザ内の処理

HTMLがブラウザに届く

ブラウザが適用する方針

この例ではCSPの設定なし

HTMLを受け取った。scriptはまだ未確認。

このSTEP時点のページ表示

https://shop.example/notice

お知らせ

正規script

未確認

混入script

未確認

「サイトが用意した」「混入した」は説明用の区別です。ブラウザは作成者や悪意を鑑定せず、方針の許可条件を確認します。

この図の前提
  • 通常のHTML文書を解析し、2つのインラインscriptを記載順に処理します。両モードともJavaScriptが有効で、他のCSP・拡張機能・sandbox等の追加制限はありません。
  • 攻撃者はこの応答のnonceを予測・取得できず、CSPヘッダーを変更できない前提です。
  • script-srcのみの最小例です。画像やフォーム等を含む完成したサイト全体の方針ではありません。[S01][S02][S04]
  • 判断と実行を学習用のSTEPに分けています。架空のページであり、コードの実行や実サイトへの送信は行いません。

同じHTMLでも、CSPの方針によってスクリプトの実行結果が変わります。この例では、nonceを持たない混入スクリプトの実行をブラウザが止めます。HTMLに混入する原因は残っているため、出力処理の修正も必要です。

STEP 01 / 4

HTMLがブラウザに届く

STEP 1 / 4: HTMLがブラウザに届く

現在のSTEP 1STEP 2STEP 3STEP 4

正規のスクリプトと、混入したスクリプトを含むHTMLが返ります。この例では、CSPは設定されていません。

技術的な詳細を見る

通常のHTML応答内のインラインscriptが処理される例です。他の実行制限がない前提です。[S01]

パネルの開閉ではSTEPは変わりません。

この概念の要点

  • 要点

    方針を伝えるのはサイト、適用するのはブラウザ。

    この例では、HTMLの応答ヘッダーでCSPを伝えます。[S01][S02]

  • 要点

    方針に合わないスクリプトの実行を止める。

    この例ではnonceが一致するコードを実行し、nonceのない混入コードを止めます。[S01]

  • 要点

    CSPはXSS対策を補う防御。

    混入を生む出力処理の修正や、安全な表示方法も必要です。[S01][S03][S05]

理解確認

この教材で、受け取ったCSPに従ってスクリプトの実行を制限するのはどれですか?

理解確認

CSPありの図で、混入したスクリプトの実行が止まった理由はどれですか?

理解確認

CSPによって混入したスクリプトの実行を止められた場合、どの対応が適切ですか?

CSPの補足

nonceはどのように使う?

nonceは、応答ごとに生成する予測困難な値です。その応答のCSPと、サイトが実行を許可するscriptへ同じ値を設定します。1つのHTML応答内では、複数の許可するscriptへ同じnonceを付けられます。[S01][S02]

ヘッダーのnonceとscriptを照合する
r4V1mQ8pL2sN6dK0xC9bHw==
  • → 同じnonceを持つscript → 一致:実行を許可
  • → nonceなしのscript → ブロック

すべてのscriptへ機械的にnonceを付けると、混入コードまで許可してしまいます。また、nonceが付いたscriptの内容に危険な入力を埋め込めば、そのコードも実行され得ます。nonceはコードの安全性を証明する署名ではありません。[S02]

  • 実際の値は暗号学的に安全な乱数で生成します。W3Cの仕様では符号化前に少なくとも128ビットを推奨しています。[S01 §7.1]
  • スクリプト内容のハッシュを方針に指定する方法もあります。静的なHTMLではハッシュを使う構成も検討されます。内容を変えればハッシュも変わります。[S02][S04]
  • 実運用の方針は参考資料S02・S04を参照します。この教材の最小例をそのままサイト全体の完成した設定としません。

nonceは秘密鍵、ファイルのハッシュ、署名、ログイントークンではありません。

スクリプト以外も制限できる?

CSPは、対象ごとに方針を指定します。script-srcを書いただけで、画像や送信先、埋め込み元もすべて制限されるわけではありません。[S01]

指定ごとに異なる対象
指定主に制限する対象
script-srcスクリプトの読み込み・実行
img-src画像の読み込み元
connect-srcfetch等のスクリプトAPIによる接続先
frame-ancestorsこのページをiframe等へ埋め込める親・祖先のページ

default-srcは、個別に指定されていない取得系ディレクティブの既定値として使われます。すべての指定の代わりになるわけではなく、frame-ancestorsには適用されません。frame-srcのような埋め込む先の指定とは向きが異なります。[S01 §6.1.3・§6.4.2]

Report-Onlyは実行を止める?

Content-Security-Policy-Report-Onlyは、方針に違反する動作を調べるための仕組みです。この方針そのものは動作をブロックしません。導入前に、正常な機能まで止めてしまわないかを確認する用途があります。[S01][S02]

検知とブロックを分ける
方針の伝え方この例の混入script
Content-Security-Policy違反を検知 → 実行をブロックする
Content-Security-Policy-Report-Onlyだけ違反を検知 → その方針では実行を止めない

サーバーへの報告収集には報告先の設定が必要です。Report-Onlyを設定しただけで、運営者へ必ず通知・保存されるわけではありません。[S01]

SOP・CORSとは何が違う?
それぞれの役割
仕組みこの教材との関係
SOPオリジンの境界を基に、別のページや資源への読み取り等を制限するブラウザの基本ルール。[S07]
CORS取得先がHTTP応答で別オリジンとの共有を許可する仕組み。API応答をJavaScriptへ公開する場面などで使う。[S06]
CSPページ側が伝えた方針に基づき、そのページの読み込み・実行等を制限する仕組み。[S01]

今回の混入scriptは、同じページの中にあります。別オリジンかどうかだけで、正規コードと混入コードを見分けられるわけではありません。

CSPのconnect-srcでAPIへの接続先を許可しても、それによってCORSの読み取り許可が得られるわけではありません。逆に、取得先がCORSを許可していても、ページ側のCSPが接続を制限することがあります。[S01][S06]

参考資料

RELATED CONCEPTS