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ヘッダに署名値が含まれる形である。
<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を利用したほうが良いのではないか?といった疑問については、上記でも上げた概要に書かれている。