1. このページの目的
このページに、CSP Level 3 を設定する。
Strict CSP (厳格なCSP)というアプローチに従う。
※ 結局、以下のリンク先で説明されている内容を翻訳した感じになってしまいました。
参考:Strict CSP
1-1. Strict CSP のための準備
Strict CSP の考え方
- CSP Level 2 の時のように「ドメインをホワイトリストに追加していく」のではなく、すべての
<script>
タグに nonce 属性を追加し、nonce に対して許可する「nonce ベース」のアプローチである。更に'strict-dynamic'
を指定することで、すでに許可したスクリプトが動的に他のスクリプトを読み込むことを許可する。<script>
タグ毎に nonce の値を別にする必要はないのでラク。- 特定のドメインを指定する必要がないのでラク。
- 基本的に、script 以外のリソース (css, style など) に対しては制御を行わない(効果が薄いため)。
- モダンブラウザでは CSP を利用した制限をかけるが、CSP Level 3 をサポートしていないレガシーなブラウザではリソースの動作を妨げないことを優先する。
Scrict CSP を適用するための準備
- すべての
<script>
タグに、nonce
属性を付ける。- リクエストがある毎に、サーバーサイドで
nonce
値を 1つ生成し、すべての<script>
タグのnonce
属性にセットする。
- リクエストがある毎に、サーバーサイドで
- イベントハンドラ属性や
javascript:
に書いた JavaScript コードがあれば、リファクタリングして他の場所に移動させる。 - ページロード毎に nonce 値を生成して、すべての
nonce
属性にセットする。 - はじめは、
Content-Security-Policy
ではなくContent-Security-Policy-Report-Only
を利用して要素を見る。
2. このページで出力しているCSP用のHTTPヘッダ
Strict CSP で説明されている内容を翻訳してまとめ直しています。
Content-Security-Policy:
object-src 'none';
script-src 'nonce-{random}' 'unsafe-inline' 'strict-dynamic' https: http:;
base-uri 'none';
report-uri https://misc.laboradian.com/
- CSSや画像などに対しては何も設定しない(効果が薄いため)。
eval()
を許可したい場合は、'unsafe-inline'
の後ろに'unsafe-eval'
を追記する。
ソース | 意味 |
---|---|
object-src 'none' |
|
script-src nonce-{random} 'unsafe-inline' |
|
script-src 'strict-dynamic' https: http |
|
'unsafe-eval' |
|
base-uri 'none' |
|
report-uri |
|
ブラウザの種類 | 動作 |
---|---|
最新のブラウザ |
|
CSP3 標準をサポートしていない古いブラウザ |
|
3. 本ページで利用しているPHPコードとHTML
$nonce = base64_encode(random_bytes(20));
header(
"Content-Security-Policy:"
. "object-src 'none';"
. "script-src 'nonce-$nonce' 'unsafe-inline' 'strict-dynamic' https: http:;"
. "base-uri 'none';"
. "report-uri https://misc.laboradian.com/"
);
<script defer src="main.js" nonce="<?php echo e($nonce); ?>"></script>
<script defer src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/highlight.min.js"
nonce="<?php echo e($nonce); ?>" ></script>
<script nonce="<?php echo e($nonce); ?>">
window.addEventListener('DOMContentLoaded', (event) => {
console.log('inline js');
hljs.highlightAll();
});
e()
はHTMLのエスケープ関数(自作)
4. 観察する
ブラウザで本ページのソースを開き、何回かリロードしてください。nonce 値が毎回変更されるのが分かります。
ブラウザの開発者ツールの Console パネルを見ます。CSP のエラーは発生していないはずです。
ブラウザの開発者ツールの Network パネルを開き、HTTPレスポンスヘッダを見て、Content-Security-Policy
の値を確認します。
5. 参考
- Content Security Policy Level 3 (W3C Working Draft, 15 October 2018)
- Content Security Policy Level 3 (Editor’s Draft, 11 January 2021)
- Introduction - Content Security Policy (Strict CSP)
- headers HTTP header: csp: Content-Security-Policy: strict-dynamic | Can I use...(ブラウザのサポート状況)