Content-Security-Policyやらsubresource integrityなどに関するメモ

最近、セキュリティに特に気をかけなければいけないサービスの開発をしていて調べた知見のメモ。

subresource integrity

Subresource Integrity - Web security | MDN

いわゆるチェックサムの仕組み。 integrity 属性に ${hashalgorithm}-${hashdigest} 形式の値を書いておき、フェッチしたファイルのハッシュ値が一致していなければブラウザが読み込みをブロックする。

これは、たとえばCDNが攻撃されるなどしてスクリプトなどが改竄された場合に有効。

JSやCSSはプリ・ポストプロセッサで処理し出力することがほとんどだろうが、subresource integrityとどうやって統合するかというとgulp-hashsumを使ってコンパイルしたファイルのハッシュ値をdigest.jsonに保存し、HTMLのレンダリング時にそれを参照してscript/link要素に埋める、という方法が考えられる。
開発しているサービスは、使っているツールセットなどの兼ね合いからこの方法をとっている。

webpack-subresource-integrityのようなプラグインもある。

Content-Security-Policy

インタラクティブな要素が少ないので、Plackミドルウェアで一律 default-src 'none' style-src 'self'を指定した後にホワイトリスト形式で追加するという運用にしている。

これでいくつかハマった点があるので紹介。

Google Tag Managerとの兼ね合い

Google Tag ManagerはHTML断片やGoogle Analyticsなどのタグタイプを選べるが、これはつまるところ動的なスクリプトの実行・読み込みなので script-src などのポリシーが適用される。

上記のようなホワイトリスト形式のポリシーと相性が少し悪い。

動的なスクリプトの実行については、都度nonceを付与するということも考えられるけど、ホワイトリスト形式で運用したいページではそもそも使わないのが手間を考えると楽かと思う。

外部スクリプト読み込みは、諦めてタグタイプを追加する度にポリシーに追加することにした。といってもGoogle Analyticsくらいしか使わないだろうから、そんなに困っていない。

複数ポリシーを指定するとorではなくandで検証される

仕様に書いてある

Content-Security-Policy: default-src 'self' http://example.com http://example.net;
                         connect-src 'none';
Content-Security-Policy: connect-src http://example.com/;
                         script-src http://example.com/

Is a connection to example.com allowed or not? The short answer is that the connection is not allowed.

Content Security Policy Level 2

たとえばデフォルトは厳しいルールを指定しておくが、エンドポイントごとに緩めたい時はデフォルトのポリシーをレスポンスヘッダから取得しマージした値をレスポンスヘッダに再度書き出すということが必要。