SRI ハッシュ生成ツール — integrity 属性つきの script / link タグを作る
CDN などにある JavaScript・CSS の URL を入れると、ファイルを実際に取得して SHA-384 の integrity 値を計算し、crossorigin 付きの script / link タグを生成します。あわせて、そのタグが本当に読み込めるか(CORS ヘッダー)と、将来ハッシュが合わなくなる要因(バージョン未固定・ブラウザごとの出し分け)も判定します。
無料・登録不要結果は保存しません(ログのみ 30 日)更新:
生成したタグはどう使いますか?
生成したタグを、元の script / link タグと置き換えて貼り付けます。integrity と crossorigin="anonymous" は必ずセットで使い、どちらかを消さないでください。ライブラリを更新するときは、新しい URL でこのツールを使い直し、URL と integrity を同時に差し替えます。
<!-- 変更前: integrity なし -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- 変更後: このツールが生成したタグで置き換える(値は例) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-(ツールが出力した値)"
crossorigin="anonymous"></script>ハッシュは、ブラウザが受け取るのと同じバイト列に対して計算しています。配信時の gzip・Brotli 圧縮は解いたうえで、文字コードの変換はしません。 そのため、UTF-8 以外で書かれたファイルや BOM 付きのファイルでも、ブラウザが検証する値と一致します。
入力した URL がリダイレクトされた場合(例: バージョンを省いた URL が特定の版へ転送される)、タグには実際に中身を返した転送先の URLを使います。転送元の URL のままだと、転送先が変わった時点でハッシュが合わなくなるためです。ファイル名が .mjs の場合は type="module" を付けたタグを出します。
このツールは何を判定していますか?
ハッシュそのものに加えて、CORS ヘッダーの有無、URL のバージョン固定、ブラウザごとの出し分け(Vary: User-Agent)、content-type、HTTPS の 5 点を判定します。ハッシュは正しくても、これらに問題があるとタグを貼った後に読み込めなくなったり、ある日突然壊れたりするためです。
| 項目 | 合格 | 注意・不合格 |
|---|---|---|
| CORS | Access-Control-Allow-Origin: *、または当ツールのオリジンを許可 | 特定の別オリジンだけ許可は注意。ヘッダーが無ければ不合格(別オリジンから読み込めない) |
| バージョン固定 | URL に完全なバージョン(@5.3.3・/3.7.1/)、コミット、?v=、内容ハッシュ入りのファイル名がある | latest、@5 のような範囲指定、バージョンを読み取れない URL は注意 |
| ブラウザごとの出し分け | Vary: User-Agent が無い | Vary: User-Agent または Vary: * があれば注意 |
| content-type | JavaScript は text/javascript など、CSS は text/css | CSS で text/css 以外は不合格。JavaScript で image/*・audio/*・video/*・text/csv は nosniff が無くても不合格(ブラウザが実行しない)、それ以外の値は nosniff 付きなら不合格、なしなら注意 |
| HTTPS | https:// で配信 | http:// は注意(HTTPS のページからは混在コンテンツとしてブロック) |
種類(JavaScript か CSS か)は content-type で判断し、決まらないときだけ拡張子で判断します。HTML が返った場合(エラーページやログイン画面)と、 転送量が 5 MB を超えて途中で打ち切った場合は、誤った値を渡さないよう、ハッシュを出しません。
なぜ crossorigin 属性と CORS ヘッダーが必要なのですか?
別オリジンのファイルに SRI を効かせるには、CORS での取得が必要だからです。別オリジンのファイルは crossorigin="anonymous" を付けて CORS で取得し、配信側が Access-Control-Allow-Origin を返して初めて検証できます。どちらかが欠けると、ブラウザはそのファイルの読み込み自体を拒否します。
別オリジンのファイルを crossorigin 属性なしで読み込むと、ブラウザはそれを中身を読めない形(no-cors)で取得します。MDN によれば、 ブラウザは no-cors の取得に SRI を使わせないため、integrity を付けたこの形のタグは常に失敗します。 一方で crossorigin="anonymous" を付けても、配信側が Access-Control-Allow-Origin を返さなければ CORS が成立せず、やはり読み込めません。
| crossorigin 属性 | 配信側の CORS ヘッダー | 結果 |
|---|---|---|
| anonymous あり | あり | ハッシュを照合し、一致すれば読み込む |
| anonymous あり | なし | CORS エラーで読み込まない |
| なし | あり・なしとも | integrity を検証できず、読み込まない |
自サイトと同じオリジンから配信するファイルなら、CORS は関係ありません。詳しくは CORS の解説を参照してください。
なぜバージョンを固定した URL を使うのですか?
integrity は今の中身のハッシュなので、中身が変わる URL だと、正規の更新でもハッシュが一致しなくなり読み込みが止まるためです。@latest や @5 のような範囲指定は新しい版が出るたびに中身が変わります。bootstrap@5.3.3 のように完全なバージョンを指定した URL を使ってください。
jsDelivr や unpkg のような npm 系の CDN では、bootstrap@5 や bootstrap@5.3 はその範囲の最新版を指し、バージョンを省くと最新版になります。 SRI と組み合わせられるのは、bootstrap@5.3.3 のように中身が二度と変わらない URLだけです。
ただし URL だけでは判断しきれない場合もあります。?v=20260926 のような付け方でも、サーバーがその値を無視して最新のファイルを返す設定なら、中身は変わります。 当ツールの判定は URL の見た目による推定なので、最終的には配信元の仕様を確認してください。
SRI を使えないのはどんなときですか?
同じ URL のまま中身が変わるリソースと、ブラウザごとに違う中身を返すリソースには使えません。Google タグマネージャー・Google アナリティクス(gtag.js)・AdSense のタグはこの型で、SRI を付けると更新のたびに読み込みが止まります。これらには付けず、出し分けるライブラリは固定した版を自サーバーから配信します。
- 同じ URL のまま中身が更新されるタグ — Google タグマネージャー、Google アナリティクスの gtag.js、AdSense の広告タグなど。 配信側が中身を更新する前提のため、ハッシュを固定できません。さらに、これらは別のスクリプトを後から読み込みます。integrity が検証するのはそのタグ自身が取得する 1 ファイルだけで、 後から読み込まれるスクリプトには及びません
- ブラウザごとに違う中身を返す配信 —
Vary: User-Agentを返す配信です。2024 年に乗っ取られた polyfill.io はこの型で、integrity をそもそも付けられませんでした。 必要なファイルを固定した版として自サーバーから配信するのが対策です - インラインのスクリプト・スタイル — integrity は外部ファイルを読み込む要素のための属性です。インラインのコードは CSP のハッシュや nonce で管理します
MDN によれば、integrity を付けられるのは <script> と、rel が stylesheet・preload・modulepreload の <link> です。 画像やフォントを直接読み込む要素には使えません。
integrity の付け忘れを防ぐには?
Integrity-Policy レスポンスヘッダーを使います。Integrity-Policy: blocked-destinations=(script) を返すと、integrity の無いスクリプトをブラウザがブロックします。MDN の互換性データでは、スクリプトへの適用は Chrome 138・Firefox 145・Safari 26 以降が対応しています。まず Report-Only 版で影響を確かめるのが安全です。
# まず違反の報告だけを受け取り、影響を確かめる
Reporting-Endpoints: integrity-endpoint="https://example.com/reports/integrity"
Integrity-Policy-Report-Only: blocked-destinations=(script), endpoints=(integrity-endpoint)
# 問題が無ければ強制に切り替える(integrity の無いスクリプトをブロック)
Integrity-Policy: blocked-destinations=(script), endpoints=(integrity-endpoint)blocked-destinations には script と style を指定できますが、MDN の互換性データでは、style(スタイルシート)への適用を既定で有効にしているブラウザは現時点でありません。Firefox 142 以降で、設定項目 security.integrity_policy.stylesheet.enabled を有効にした場合だけ働きます。 未対応のブラウザではヘッダーが無視されるので、各タグに integrity を付ける運用が土台であることは変わりません。 このヘッダーは、integrity の無いスクリプトに加えて、no-cors での取得もブロックします。
ハッシュを手元で計算するには?
openssl コマンドで計算できます。ファイルを openssl dgst -sha384 -binary に通し、openssl base64 -A で Base64 にした文字列の先頭に sha384- を付けたものが integrity の値です。このツールの結果と一致すれば、配信されているファイルと手元のファイルが同じだと確認できます。
# 手元のファイルから計算する
openssl dgst -sha384 -binary lib.min.js | openssl base64 -A
# 配信中のファイルから計算する
curl -s https://cdn.example.com/lib@1.4.2/lib.min.js \
| openssl dgst -sha384 -binary | openssl base64 -A
# 動作確認用: 中身が「alert(1)」だけなら次の値になる
printf 'alert(1)' | openssl dgst -sha384 -binary | openssl base64 -A
# → HT2E9NfWiuQ/w1PRai+hTyqW16NIoCGA/m8VQDUopfAtcz6YQjtsMmQd5uRbVDpWcurl に --compressed を付けても付けなくても、パイプに流れるのは解凍後の中身なので、結果は同じです。 ブラウザの開発者ツールで、タグの integrity を 1 文字書き換えて再読み込みし、コンソールに整合性エラーが出てファイルがブロックされれば、検証が働いていることを確認できます。
よくある質問
sha384 と sha512 はどちらを使えばよいですか?
どちらでも同じように機能します。sha384 が最も広く使われており、CDN の配布ページやこのツールの既定値も sha384 です。より強いアルゴリズムを使いたい場合は sha512 を選んでも構いません。両方を併記すると、ブラウザは強い方(sha512)だけを照合します。
タグを貼ったらファイルが読み込まれなくなりました。
開発者ツールのコンソールを確認してください。integrity の不一致なら、配信中のファイルがハッシュ計算時から変わっています。CORS のエラーなら、配信側が Access-Control-Allow-Origin を返していないか、crossorigin 属性が欠けています。URL にバージョンが固定されているかもあわせて確認してください。
自分のサイトのファイルにも SRI は必要ですか?
通常は不要です。SRI が防ぐのは、CDN など外部の配信元が侵害されてファイルをすり替えられる事態です。自サーバーのファイルが改ざんされる状況では、HTML も同じく改ざんされうるため効果は限られます。外部から読み込むスクリプトと CSS を優先してください。
入力した URL にはどのようにアクセスしますか?
入力された URL に通常の GET リクエストを送り、ファイルを 1 回取得します。リダイレクトを含めて最大 6 リクエスト、転送量 5 MB までで、それを超えるファイルはハッシュを出しません。結果は保存しません(入力内容は障害調査用のログに 30 日残ります)。