サブリソース完全性 (Subresource Integrity) (SRI) は、 (CDN などから) 取得したリソースが意図せず改ざんされていないかをブラウザーが検証するセキュリティ機能です。 SRI を利用する際には、取得したリソースのハッシュ値と一致すべきハッシュ値を指定します。

メモ: サブリソース完全性の検証において、サブリソースが埋め込まれる文書のオリジン以外から提供されたリソースについては、ブラウザーはオリジン間リソース共有 (CORS) を使用してリソースに追加のチェックを行い、オリジンがリソースがリクエストしたオリジンに共有されることを許可しているかどうかを確認します。

サブリソース完全性の必要性

複数のサイトで使われるスクリプトやスタイルシートなどのファイルをコンテンツ配信ネットワーク (CDN) にホストすることにより、読み込みに必要な時間や通信帯域を減らすことができます。しかし、 CDN はリスクにもなり得ます。仮に攻撃者が CDN を掌握できれば、攻撃者は CDN 上のファイルに悪意あるコンテンツを挿入することにより (あるいは完全に置き換えることにより)、その CDN からファイルを読み込む全てのサイトを攻撃対象とすることができます。

サブリソース完全性は、ウェブアプリケーションやウェブ文書が (CDN など任意の場所から) 取得したファイルについて、第三者によってファイルの中に別のものが挿入されていないか、そして、それらのファイルに対してその他の改ざんが行われていないかを検証することにより、先程のような攻撃のリスクを軽減します。

サブリソース完全性の使い方

サブリソース完全性の機能は、ブラウザーが取得するリソース (ファイル) のハッシュ値を base64 エンコードし、その値を <script><link> 要素の integrity 属性に指定することによって使用します。

integrity 属性の値は、ハッシュアルゴリズムを示す接頭辞 (現在利用できる接頭辞は sha256, sha384, sha512 です) と、 base64 でエンコードされたハッシュ値をダッシュで繋いだ文字列です。

メモ: integrity 属性値には、ホワイトスペースで区切って複数のハッシュ値を含めることができます。リソースはこれらのハッシュ値のいずれかに一致した場合に読み込まれます。

base64 でエンコードされた sha384 ハッシュを含む integrity 文字列の例

sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC

従って、 oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC がハッシュ値の部分であり、接頭辞の sha384 が sha384 ハッシュであることを示します。

メモ: 厳密に言うと、 integrity 属性値におけるハッシュ値の部分は、あるハッシュ関数にデータを入力 (スクリプトやスタイルシートファイル) して生成された暗号学的ダイジェスト値です。しかし、一般的には短く「ハッシュ」と言えば暗号学的ダイジェスト値を意味するので、本記事でもそのように呼んでいます。

SRI ハッシュを生成するツール

次の openssl コマンドにより SRI ハッシュを生成することができます。

cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A

または、次のような shasum コマンドの呼び出しでも実現できます。

shasum -b -a 384 FILENAME.js | awk '{ print $1 }' | xxd -r -p | base64

メモ:

  • パイプで xxd を通る過程で、 shasum からの出力を取り、バイナリへ変換します。
  • パイプで awk を通る過程は、 shasum がハッシュ化されたファイル名を xxd へ渡すために必要です。ファイル名が有効な16進数の文字を持っている場合に有害な影響を与える可能性があるからです。 xxd はそれを復号して、 base64 に渡す可能性があるからです。

また、SRI Hash Generator (https://srihash.org/) によりオンラインで SRI ハッシュを生成することもできます。

コンテンツセキュリティポリシーとサブリソース完全性

Content Security Policy を使用すると、特定の種類のファイルに対して サブリソース完全性の使用をサーバーに強制するよう設定することができます。このためには、以下のように CSP ヘッダーで require-sri-for ディレクティブを使用します。

Content-Security-Policy: require-sri-for script;

これは JavaScript を読み込むとき、 サブリソース完全性情報があってチェックに通った場合のみ成功として扱います。

スタイルシートを読み込むときに SRI を使用するように指定することもできます。

Content-Security-Policy: require-sri-for style;

script および style の両方を指定し、両方の種類のファイルに SRI を強制することもできます。

オリジン間リソース共有とサブリソース完全性

サブリソース完全性の検証において、サブリソースが埋め込まれる文書のオリジン以外から提供されたリソースについては、ブラウザーはオリジン間リソース共有 (CORS) を使用してリソースに追加のチェックを行い、オリジンがリソースがリクエストしたオリジンに共有されることを許可しているかどうかを確認します。従って、次の例のように、リソースが要求されたオリジンに共有できるよう Access-Control-Allow-Origin ヘッダーを付けて提供する必要があります。

Access-Control-Allow-Origin: *

以下の例では、 oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC が特定のスクリプト example-framework.js の期待される SHA-384 ハッシュ値としてすでに知られており、スクリプトのコピーが https://example.com/example-framework.js にホストされているものとします。

<script> 要素のサブリソース完全性

次の <script> 要素により、ブラウザーが https://example.com/example-framework.js を実行する前に、まず想定されるハッシュ値とスクリプトのハッシュ値が一致することをブラウザーに確認させることができます。

<script src="https://example.com/example-framework.js"
        integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
        crossorigin="anonymous"></script>

メモ: crossorigin 属性については CORS 設定属性を参照してください。

サブリソース完全性のブラウザーでの扱い

ブラウザーは SRI を以下のように処理します。

  1. ブラウザーは integrity 属性を持った <script> または <link> 属性を見つけると、スクリプトや <link> 属性で指定された任意のスタイルシートを適用する前に、integrity 属性のハッシュ値とスクリプトやスタイルシートのハッシュ値を比較しなくてはなりません。

  2. メモ: サブリソース完全性の検証において、サブリソースが埋め込まれる文書のオリジン以外から提供されたリソースについては、ブラウザーはオリジン間リソース共有 (CORS) を使用してリソースに追加のチェックを行い、オリジンがリソースがリクエストしたオリジンに共有されることを許可しているかどうかを確認します。

  3. スクリプトやスタイルシートが対応する integrity 属性値と一致しない場合、ブラウザーはスクリプトを実行したりスタイルシートを適用してはいけません。その代わりに、スクリプトやスタイルシートの取得が失敗したというネットワークエラーを返さなくてはなりません。

仕様書

仕様書 状態 備考
Subresource Integrity 勧告
Fetch 現行の標準

ブラウザーの対応

<script integrity>

Update compatibility data on GitHub
デスクトップモバイル
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOS 版 SafariSamsung Internet
基本対応Chrome 完全対応 45Edge 部分対応 17Firefox 完全対応 43IE 未対応 なしOpera 完全対応 ありSafari 完全対応 ありWebView Android 完全対応 45Chrome Android 完全対応 45Edge Mobile 未対応 なしFirefox Android 完全対応 43Opera Android ? Safari iOS 未対応 なしSamsung Internet Android 完全対応 5.0

凡例

完全対応  
完全対応
部分対応  
部分対応
未対応  
未対応
実装状況不明  
実装状況不明

CSP: require-sri-for

Update compatibility data on GitHub
デスクトップモバイル
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOS 版 SafariSamsung Internet
基本対応
実験的
Chrome 完全対応 54Edge 未対応 なしFirefox 完全対応 49
無効
完全対応 49
無効
無効 From version 49: this feature is behind the security.csp.experimentalEnabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
IE 未対応 なしOpera 完全対応 41Safari 未対応 なしWebView Android 完全対応 54Chrome Android 完全対応 54Edge Mobile 未対応 なしFirefox Android 完全対応 49
無効
完全対応 49
無効
無効 From version 49: this feature is behind the security.csp.experimentalEnabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
Opera Android 完全対応 41Safari iOS 未対応 なしSamsung Internet Android 完全対応 6.0

凡例

完全対応  
完全対応
未対応  
未対応
実験的。動作が変更される可能性があります。
実験的。動作が変更される可能性があります。
ユーザーが明示的にこの機能を有効にしなければなりません。
ユーザーが明示的にこの機能を有効にしなければなりません。

関連情報

ドキュメントのタグと貢献者

このページの貢献者: mfuji09, reioto, hashedhyphen, satakeh
最終更新者: mfuji09,