サブリソース完全性
サブリソース完全性 (Subresource Integrity, SRI) は、(CDN などから)取得したリソースが意図せず改ざんされていないかをブラウザーが検証するセキュリティ機能です。 SRI を利用する際には、取得したリソースのハッシュ値と一致すべきハッシュ値を指定します。
メモ: サブリソース完全性の検証において、サブリソースが埋め込まれる文書のオリジン以外から提供されたリソースについては、ブラウザーはオリジン間リソース共有 (CORS) を使用してリソースに追加のチェックを行い、オリジンがリソースがリクエストしたオリジンに共有されることを許可しているかどうかを確認します。
サブリソース完全性の必要性
複数のサイトで使われるスクリプトやスタイルシートなどのファイルをコンテンツ配信ネットワーク (CDN) にホストすることにより、読み込みに必要な時間や通信帯域を減らすことができます。例えば、 https://example.com
から提供される文書内のリソースには、別の場所から取得したリソースを入れることができます。
<script src="https://not-example.com/script.js"></script>
これはリスクにもなり得ます。仮に攻撃者が CDN を掌握できれば、攻撃者は CDN 上のファイルに悪意あるコンテンツを挿入することにより(あるいは完全に置き換えることにより)、その CDN からファイルを読み込む全てのサイトを攻撃対象とすることができます。
サブリソース完全性は、ウェブアプリケーションやウェブ文書が (CDN など任意の場所から) 取得したファイルについて、第三者によってファイルの中に別のものが挿入されていないか、そして、それらのファイルに対してその他の改ざんが行われていないかを検証することにより、先程のような攻撃のリスクを軽減します。
サブリソース完全性の使い方
サブリソース完全性の機能は、ブラウザーが取得するリソース (ファイル) のハッシュ値を base64 エンコードし、その値を <script>
要素や、 rel="stylesheet"
、rel="preload"
、rel="modulepreload"
のついた <link>
要素の integrity
属性に指定することによって使用します。
integrity
属性の値は、ハッシュアルゴリズムを示す接頭辞 (現在利用できる接頭辞は sha256
, sha384
, sha512
です) と、 base64 でエンコードされたハッシュ値をダッシュで繋いだ文字列です。
メモ: integrity
属性値には、ホワイトスペースで区切って複数のハッシュ値を含めることができます。リソースはこれらのハッシュ値のいずれかに一致した場合に読み込まれます。
base64 でエンコードされた sha384 ハッシュを含む integrity
文字列の例
sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
従って、 oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
がハッシュ値の部分であり、接頭辞の sha384
が sha384 ハッシュであることを示します。
メモ:
厳密に言うと、 integrity
属性値におけるハッシュ値の部分は、あるハッシュ関数にデータを入力(スクリプトやスタイルシートファイル)して生成された暗号学的ダイジェスト値です。しかし、一般的には短く「ハッシュ」と言えば暗号学的ダイジェスト値を意味するので、本記事でもそのように呼んでいます。
SRI ハッシュを生成するツール
SRI ハッシュジェネレーター
SRI ハッシュジェネレーターは、 SRI ハッシュを生成することができるオンラインツールです。
OpenSSL の使用
OpenSSL を使用して、次のようなコマンドを呼び出すことで、コマンドラインから SRI ハッシュを生成することができます。
cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A
Windows 環境では、次のコードで SRI ハッシュを生成するツールを作成することができます。
@echo off
set bits=384
openssl dgst -sha%bits% -binary %1% | openssl base64 -A > tmp
set /p a= < tmp
del tmp
echo sha%bits%-%a%
pause
このコードを使用するには、次のようにしてください。
- こののコードを、
sri-hash.bat
という名前で、自分の環境の Windows の「送る」フォルダー内(例えば、C:\Users\USER\AppData\Roaming\Microsoft\Windows\SendTo
)に保存してください。 - ファイルエクスプローラーでファイルを右クリックし、送るを選択してから
sri-hash
を選択します。コマンドボックスに完全性の値が表示されます。 - 完全性の値を選択し、右クリックしてクリップボードにコピーします。
- 任意のキーを押し、コマンドボックスを閉じます。
メモ: OpenSSL がシステムにインストールされていない場合は、 OpenSSL プロジェクトのウェブサイトで、ダウンロードおよびインストールに関する情報を確認してください。 OpenSSL プロジェクトは、 OpenSSL のバイナリーを配布していませんが、サードパーティーの配布に関する非公式なリストを https://wiki.openssl.org/index.php/Binaries で管理しています。
shasum の使用
SRI ハッシュの生成は、 shasum を次のように呼び出すことで使用することもできます。
shasum -b -a 384 FILENAME.js | awk '{ print $1 }' | xxd -r -p | base64
- パイプで
xxd
を通る過程で、shasum
からの出力を取り、バイナリーへ変換します。 - パイプで
awk
を通る過程は、shasum
がハッシュ化されたファイル名をxxd
へ渡すために必要です。ファイル名が有効な 16 進数の文字を持っている場合に有害な影響を与える可能性があるからです。xxd
はそれを復号して、base64
に渡す可能性があるからです。
オリジン間リソース共有とサブリソース完全性
サブリソース完全性の検証において、サブリソースが埋め込まれる文書のオリジン以外から提供されたリソースについては、ブラウザーはオリジン間リソース共有 (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 を以下のように処理します。
-
ブラウザーは
integrity
属性を持った<script>
または<link>
属性を見つけると、スクリプトや<link>
属性で指定された任意のスタイルシートを適用する前に、integrity
属性のハッシュ値とスクリプトやスタイルシートのハッシュ値を比較しなくてはなりません。サブリソース完全性の検証において、サブリソースが埋め込まれる文書のオリジン以外から提供されたリソースについては、ブラウザーはオリジン間リソース共有 (CORS) を使用してリソースに追加のチェックを行い、オリジンがリソースがリクエストしたオリジンに共有されることを許可しているかどうかを確認します。
-
スクリプトやスタイルシートが対応する
integrity
属性値と一致しない場合、ブラウザーはスクリプトを実行したりスタイルシートを適用してはいけません。その代わりに、スクリプトやスタイルシートの取得が失敗したというネットワークエラーを返さなくてはなりません。
仕様書
Specification |
---|
HTML # attr-link-integrity |
Subresource Integrity # the-integrity-attribute |
HTML # attr-script-integrity |