署名式 SRI(Subresource Integrity)の議論

W3CのWeb Application Securityワーキンググループで、署名式 SRIの議論が出ていたので簡単に書く

背景

セキュリティ向上の目的で、Webページ上で読み込まれるリソース(JavaScript等)を制限する方法に、CSP(Content Security Policy)やSRI(Subresource Integrity)と言った技術がある。

CSP

CSPを利用することで、読み込むJavaScriptを信頼できるURLのみに制限出来る。

CSPのscript-srcディレクティブで、以下のように制限できる。

script-src https://example.com/script/trusted.js


しかし、CSP Is Dead, Long Live CSP! On the Insecurity of Whitelists and the Future of Content Security Policyで述べられているように、URLベースの制限は非常に細かく記述する必要があり、大規模なサービスでちゃんと運用することは難しい面があるようです。

SRI

SRIを利用することで、リソースが本当に意図したものである場合のみ読むこむように出来ます。

scriptタグのintegirty属性にコンテンツのハッシュ値を付与することで、リソースの正当性が評価されます。これは、CDNなどを利用してる時に、CDNによる悪意ある改ざんから防ぐことが出来ます。

<script src="https://example.com/example-framework.js"
        integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7"
        crossorigin="anonymous"></script>

しかし、SRIはリソースの更新の順番に課題があり、リソース自体の更新とscriptタグ側のintegrity値の更新を行われなければなりません。

署名式 SRI

W3CのWeb Application Securityワーキンググループのメーリングリストで、GoogleのMike Westより「Proposal: Signatures in SRI.」として投げかけられました。

まだ、議論の段階だが概要についても、W3Cのリポジトリで公開されている。

Ed25519公開鍵で署名し、リソースの正当性を担保する。scriptタグ側に公開鍵を、HTTPレスポンスのIntegrityヘッダに署名値が含まれる形である。

javascriptタグ

<script src="https://my.cdn.com/whatever.js" integrity="ed25519-[base64-encoded public key]">

HTTPレスポンス

HTTP/1.1 200 OK
Accept-Ranges: none
Vary: Accept-Encoding
Content-Type: text/javascript; charset=UTF-8
Access-Control-Allow-Origin: *
...
Integrity: ed25519-[base64-encoded result of Ed25519(`console.log("Hello, world!");`)]
 
console.log("Hello, world!");

この方式であればCDNを利用していても、与えられた公開鍵で署名値を確認することで、意図してないリソースを読み込む(実行する)事は防がれる。また、javascriptタグ側の変更は不要である点もメリットとしてあり、これでSRIにあった更新順序の問題は解決される。


実際に需要があるのか?古いバージョンのファイルを提供する攻撃が可能か?鍵管理が困難ではないのか?PKIやX.509を利用したほうが良いのではないか?といった疑問については、上記でも上げた概要に書かれている。