Content Security Policy (CSP) の振り返り

フィッシング詐欺
©いらすとや.

Content Security Policy (CSP)は、ウェブサイト側で定めたポリシーに従ってブラウザがコンテンツ(の要素)を表示する/表示しないまたは外部サイトにそのサイトの要素を表示させる/表示させないことによって閲覧者を守るセキュリティ。ウェブサイトに脆弱性があるなどしてクロスサイト・スクリプティングを仕掛けられようとしても閲覧者が守られる可能性はあるが、ウェブサーバを守るセキュリティということではないので手を付けないウェブサイトオーナーさんも多い。でも、閲覧者を守るというのは結局はウェブサイト(運営母体)のブランドも守ることになるのでしっかり考慮して設定したいところ。これは企業はもちろん個人ブログの類であっても。

Content Security Policy Level 1 (CSP1) (オワコン)

HTTPレスポンスヘッダ
Content-Security-Policy: default-src 'self';
                         script-src trustedscripts.example.com 'unsafe-inline' 'unsafe-eval';
                         object-src media1.example.com media2.example.com *.cdn.example.com;
                         frame-src frame1.example.com;
                         font-src font1.example.com font2.example.com *.cdn.example.com;
                         img-src *;

上は見易いように改行して複数行になっているが、実際には改行しないで1行。

以前よく見かけたというか現在もよく見かけるCSPの指定。ページに読み込む許可を与えるコンテンツの種類毎にself(ウェブのホスト自身)と外部のホスト/ドメイン(ワイルドカード可)を指定するので一見とっつきやすいのだけれど外部のサービスを利用するとどのホスト/ドメインから読み込むかしっかり調べてリストアップしなければならないが、読み込み許可しなければならないホスト/ドメインが増えたり変更になったときに面倒というか正直追いきれないことがある。結果的に * (全て)のようなユルユルな指定をしてCSPを設定する意味がなくなってしまうことがよくある。ウェブ広告を利用する/YouTubeやGoogleMapsの地図を貼り付けるなど外部サービスを利用するとそうなりやすいというかなる。
もちろん、全ての要素(画像/Javascript/CSS/フレームなど)が自身のウェブサイトにあるとかウェブフォントを外部1箇所から取るだけとかであれば全く面倒なく強固な指定ができる。

Content Security Policy Level 2 (CSP2)

HTTPレスポンスヘッダ
Content-Security-Policy: script-src 'self'
                                    https://example.com
                                    'nonce-ナンス文字列1'
                                    'nonce-ナンス文字列2';
                         base-uri 'self';
ページの中
<script nonce="ナンス文字列1" src="https://hoge.example.com/hage.js"></script>
<script nonce="ナンス文字列2" src="https://foo.example.com/bar.js"></script>
hash(ハッシュ)指定の例
HTTPレスポンスヘッダ
Content-Security-Policy: script-src 'self'
                                    https://example.com
                                    'sha256-スクリプトのハッシュ1'
                                    'sha256-スクリプトのハッシュ2';
                         base-uri 'self';
ページの中
<script>The quick brown fox jumps over the lazy dog.</script>   The〜dog.のハッシュを求める→ハッシュ1
<script>The rain in Spain stays mainly in the plain.</script>   The〜plain.のハッシュを求める→ハッシュ2

レベル1から大きく変わっている。
使用するディレクティブ (script-src, frame-src, font-srcのようやつ)が追加、変更(+非推奨化)されている。整理された筈なのに解りにくくなってるのがこれ。
ページ表示するために他所の要素(画像/スクリプト/フォントなど)を使用することを許可/不許可するのではなく、自身のサイトを外部のサイトに使わせる/使わせないための指定が追加。(frame-ancestors)
nonceやhashで個別に要素を許可できる。
など、いろいろあるのでご確認ください。

CSP Lv1より難しくなった感はある。特にnonceとhashはとっつきにくい。

Content Security Policy Level 3 (CSP3) 草案

nonse(ナンス)指定の例
HTTPレスポンスヘッダ
Content-Security-Policy: script-src 'strict-dynamic'
                                    'nonce-ナンス文字列1'
                                    'nonce-ナンス文字列2';
                         base-uri 'self';
ページの中
<script nonce="ナンス文字列1" src="https://hoge.example.com/hage.js"></script>
<script nonce="ナンス文字列2" src="https://foo.example.com/bar.js"></script>
hash(ハッシュ)指定の例
HTTPレスポンスヘッダ
Content-Security-Policy: script-src 'strict-dynamic'
                                    'sha256-スクリプトのハッシュ1'
                                    'sha256-スクリプトのハッシュ2';
                         base-uri 'self';
ページの中
<script>The quick brown fox jumps over the lazy dog.</script>  The〜dog.のハッシュを求める→ハッシュ1
<script>The rain in Spain stays mainly in the plain.</script>  The〜plain.のハッシュを求める→ハッシュ2

CSP2で追加されたchild-srcディレクティブはframe-srcを代替するものの筈でしたがchild-srcを使わなければ引き続きframe-srcで良いらしい。worker-srcも同様?
CSP2で追加になったnonceとhashは仕組みとしては手間がかかる。しかし'strict-dynamic'が追加されたおかげでこれが生きるものになった。 というのも、例えば許可した(信頼した)Javascriptが別の外部要素を呼び出した際、それを追加許可しなくて済むので本当にラクになった。

CSP2で追加になったhashはインラインスクリプトにしか使えない。これはページ内の <script>hogehoge</script> には使えるけど <script src="https://example.com/hagehage.js"></script> には使えない、つまり外部スクリプトには使えない。これがCSP3ではhashが外部スクリプトにも使えるようになる。ただし、書き方が少し違うらしいのとブラウザの対応がまだ追いついていないかも。(つまり「まだ」メジャーブラウザでも使えないかも)

外部スクリプトをhashで許可できるのは一見喜ばしいことかもしれないが、(知らない内に)その外部スクリプトに変更が加わると利用できなくなるので実は筋悪ではないかと思う。個人的には外部スクリプトを内部スクリプトから呼び出すようにして、その内部スクリプトのハッシュで許可するのが良いかと思う。

次回、実際にCSP3を設定する。
その際、AdSenseやGoogle Analyticsなど外部サービスを利用する場合に対応した実用的なものにする予定。