Content Security Policyの今後(2016年10月現在)
先月の勉強会での発表の内容と少し重なりますが、CSPの各レベルの仕様とブラウザ対応状況などのまとめです。
Content Security Policyとは
CSP (Content Security Policy) - Web セキュリティ | MDN
ざっくりですが、WebサイトからXSSの危険を取り除くための仕様です。
現在は、サーバ側でHTTPヘッダーにCSPを追加することで利用できます。
きちんと指定すればWebサイトの安全性が高まるということで、私もJavaScriptがいろいろしているサイトには導入してみているのですが、まだまだ仕様が変わっていきそうな雰囲気ですね・・・。
Content Security Policy Level1
W3Cの公式ページ
Content Security Policy 1.0
※最終バージョンの内容はここにある↓
https://www.w3.org/TR/2012/CR-CSP-20121115/
ブラウザ対応状況
主な機能
- 「default-src」「script-src」「style-src」等のディレクティブに、コンテンツの読み込みを許可するドメインを指定できる
- inlineでの実行を許可するかどうかを指定できる
- script-src(JavaScript)に関しては、evalの実行を許可するかどうかを指定できる
- レポートの機能
Content Security Policy Level2
W3Cの公式ページ
Content Security Policy Level 2
2016年10月現在勧告候補
ブラウザ対応状況
Can I use... Support tables for HTML5, CSS3, etc
- モダンブラウザはほぼ実装済み。
- Edgeは開発中というステータスになっている。
- HTMLのメタタグでもポリシーの指定ができるように
- IETFで策定されていたX-Frame-Optionsが取り込まれた
- nonceまたはhashを使ったホワイトリストが利用できるように(これについては後述)
Content Security Policy Level3
W3Cの公式ページ
Content Security Policy Level 3
- Working draftの段階なので、ブラウザ実装等はこれからと思われる。
- fetchやService Workersなどの、新しい(?)仕様への対応
- strict-dynamic他、いくつかのディレクティブの追加
いろいろと追加されているようですが、草案段階なのでまだ変わるかもしれないですね。
本当に安全なのか問題
Googleのエンジニアによる論文
発表のスライドでも触れましたが、CSP Is Dead, Long Live CSP! On the Insecurity of Whitelists and the Future of Content Security Policy という論文が発表されています。
これによれば、現在のCSPではXSSの危険を完全に取り除けているケースはほとんどないそうです。
特にホワイトリスト経由の攻撃が可能である場合が多い、と指摘されているのですが、
そうなると外部ドメインからJavaScriptを読み込む場合は、CSP(Level 1)ではXSSを防げないことになります。
論文中ではそこで、CSP Level2および3で実装予定のnonceとstrict-dynamicが有効だ、と述べられています。
が、CSPの実装を待てず(?)に、XSS-Protectionヘッダという新しい仕様の提案も出ているようです。
こちらが詳しいです:
XSSを防ぐ新しいXSS-Protectionヘッダ - あすのかぜ
使う側としては、仕様の混在はできれば避けてほしいところですが、今後どうなるのでしょうか。
nonceによるホワイトリスト
※CSP Level 2における「nonce」についてです。XSS-Protectionのnonceはまた別の仕様です。
例えば、https://example.comから、JavaScriptファイルを読み込みたい、とします。
Level 1では以下のようにCSPを記述していました。
Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com
Level 2では、上記に加えてnonceを利用した記述ができるようになります。
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-Nc3n83cnSAd3wc3Sasdfn939hc3'
HTML側でexample.comのJavaScriptファイルを読み込むときには、
<script src="https://example.com/lib.js" nonce="Nc3n83cnSAd3wc3Sasdfn939hc3"></script>
のようにすれば読み込むことができます。
どちらもホワイトリストの指定ですが、nonceを使用するほうが安全性が高い、と前述の論文でも述べられています。
また、JavaScriptだけでなく、例えばCSSを外部から読み込む場合も、同様にして使用できます。
hashによるホワイトリスト
こちらはなかなか豪快(?)な仕様です。
インラインスクリプトのコードを暗号化したものをあらかじめCSPに記述しておくと、そのコードは実行可能、というものです。
なので、CSPのほうには暗号を記述します:
Content-Security-Policy: script-src 'sha512-YWIzOWNiNzJjNDRlYzc4MTgwMDhmZ..............'
例として考え付くのは、Google Analyticsのコードを暗号化したものを指定しておき、
HTML側ではいつもの(?)var _gaq = 〜のようなAnalyticsのコードを貼り付ける、という場合でしょうか。
※CSPではデフォルトでinline-scriptを許可しておらず、また許可してしまうと安全性は下がるので、不許可が好ましいのですが、
そうするとGoogle Analyticsのコードをわざわざ個別のファイルにしてのように読み込む必要がありました。
このhashを使えば外部ファイルにする必要はなくなります。
strict-dynamicとは
JavaScriptを対象とした仕様です。
こちらはLevel 3からの仕様なので、今後変わるかもしれませんが、2016年10月現在の仕様書によれば以下のようなものです。
仕様書の例そのままですが、
Content-Security-Policy: script-src 'nonce-abcdefg' 'strict-dynamic'
のようにCSPを記述し、HTMLでは以下のようにJavaScriptを読み込むとします。(nonceが一致しているので読み込まれます!)
<script src="https://cdn.example.com/script.js" nonce="abcdefg" ></script>
さらに、
「https://cdn.example.com/script.js」内に以下のようなコードがあるとします。
document.write('<scr' + 'ipt src="/sadness.js"></scr' + 'ipt>');
このとき、「'strict-dynamic'」があると、この「sadness.js」は読み込まれません。
(逆に考えると、CSP Level2までは読み込めてしまうということですよね・・・だから安全でない、と言われるのでしょうか。)
ただし、
var s = document.createElement('script'); s.src = 'https://othercdn.not-example.net/dependency.js'; document.head.appendChild('s');
のような記述の場合は読み込めるそうです。
おわりに
仕様書やら論文やら、それなりにまじめに読んだつもりですが、そこまで英語に自信があるわけでもなく、おかしな解釈をしている点があるかもしれません。
何かお気付きの点があればコメントいただければ幸いです。