結論(外部JavaScriptのSRI)
外部JavaScriptのSRIとは、CDNなど別オリジンから読み込むスクリプトの改ざんを、ハッシュ値で検出する仕組み(Subresource Integrity)です。script 要素の integrity 属性に期待するファイルのハッシュ値(sha256・sha384・sha512)を書き、ブラウザが取得した内容のハッシュと一致しない場合に実行を拒否させます。配信元でファイルが改ざんされても、利用者のブラウザで悪性コードが実行されることを防げます。別オリジンでは crossorigin 属性とCORSも必要です。
この記事のポイント
- SRIは integrity="sha384-…" のように書き、ハッシュが一致しないスクリプトは実行されません。
- 空の integrity や md5 など未対応アルゴリズムだけの値は、ブラウザが検証しないため保護になりません。
- 別オリジンのスクリプトには crossorigin="anonymous" が必要で、配信元が Access-Control-Allow-Origin を返す必要があります。
- 版固定のファイルにだけ使え、解析タグ・タグマネージャーなど内容が変わる動的スクリプトには通常付けられません。
- セキュリティAIチェッカーは、有効なSRIのない外部JavaScriptが1件でもあれば△と判定します。
| 診断項目名 | 外部JavaScriptのSRI |
|---|---|
| 項目ID | html.sri |
| 分類 | HTML・JavaScript・外部資産 |
| 重大度・配点の重み | 中(medium) 重み 2 |
| 関連する標準・ガイドライン | OWASP ASVS 5.0.0 V3.6.1(L3: 外部ホストの資産は静的かつ版固定で、SRIで完全性を検証する場合に限る)/W3C Subresource Integrity/CWE-353(完全性チェックの欠如)、CWE-829 |
外部JavaScriptのSRI(Subresource Integrity)とは
外部JavaScriptのSRIとは、CDNなど別オリジンから読み込む script 要素に integrity 属性として期待するファイルのハッシュ値を書いておき、ブラウザが取得した内容のハッシュと一致しない場合に実行を拒否させる仕組み(Subresource Integrity)です。
CDNや外部サーバーで配信ファイルが改ざんされても、自治体サイトの利用者のブラウザ上で悪性コードが実行されることを防げます。セキュリティAIチェッカーのこの項目は、トップページで読み込まれている外部JavaScriptのうち、有効な integrity 属性を持たないものの件数を確認します。
<script src="https://cdn.example.net/lib/1.2.3/lib.min.js"
integrity="sha384-(ファイルのSHA-384ハッシュをBase64で表した値)"
crossorigin="anonymous"></script>
外部CSSのSRIは「外部CSSのSRI」で別に確認します。
SRIの仕組みとW3C仕様の要点
W3CのSRI仕様の要点は次のとおりです。
- 対応アルゴリズム:準拠するブラウザはSHA-256、SHA-384、SHA-512をサポートしなければなりません。複数のハッシュを空白区切りで書くと、最も強いアルゴリズムの値が照合に使われます。
- 有効なメタデータがない場合は検証が行われません。 仕様の照合アルゴリズムには「解析したメタデータが空集合ならtrueを返す」とあり、未対応のハッシュ関数による指定は「integrityの値が指定されなかったのと同じ」に扱われます。つまり
integrity=""やintegrity="md5-..."は保護になりません。 - CORSが前提:仕様は「CORSなしでSRIを使おうとするのは論理的な誤り」としています。別オリジンのスクリプトには
crossorigin="anonymous"を付け、配信元がAccess-Control-Allow-Originを返す必要があります。これがないと、ハッシュが正しくても読み込みが失敗します。 - 対象要素:
scriptとlink(スタイルシート等)です。
SRIが使えるスクリプト・使えないスクリプト
SRIは「内容が固定されたファイル」にしか使えません。ASVS 5.0.0 V3.6.1が「静的で版が固定された」資産に限定しているのはこのためです。
| 種類 | SRI |
|---|---|
CDNの版固定ライブラリ(.../3.7.1/jquery.min.js) | 適用可能 |
latest や版指定なしのURL | 内容が変わるため不可(版固定が先) |
| アクセス解析・タグマネージャー・広告・地図API・reCAPTCHA等の動的スクリプト | 提供元が随時更新するため、通常は適用不可 |
| ブラウザやUAによって内容が変わる配信(例: polyfill.io) | 不可 |
動的スクリプトにSRIを付けられないこと自体は異常ではありません。その場合は、配信元の信頼性評価、契約、CSPによる配信元限定、iframeによる隔離などで補います。版固定そのものは「外部資産のバージョン固定」で確認します。
SRIについてよくある誤解
- 「
integrity属性があれば安全」:値が空や不正なら検証されません。 - 「SRIを付ければ外部サービスが侵害されても大丈夫」:版固定のファイルには有効ですが、動的スクリプトには付けられないため、最も多い依存先(解析タグ等)は守れません。
- 「同一オリジンのファイルにもSRIが必要」:必須ではありません。この項目は外部オリジンのみを対象とします。
- 「ハッシュはMD5やSHA-1でもよい」:仕様が求めるのはSHA-256・SHA-384・SHA-512です。それ以外のアルゴリズムだけを書いた場合は、検証が行われません。
外部JavaScriptのSRIの診断基準(セキュリティAIチェッカー)
取得対象
- 入力URLのリダイレクト後の最終URLのHTML本文(最大2MB)を対象にします。
<script ... src="...">のうち、URLを解決したオリジンがページのオリジンと異なるもの(「外部JavaScript依存数」と同じ集合)を評価します。
「有効なSRI」の条件
integrity 属性(data-integrity 等の別属性は除く)の値(空白区切りで複数指定可)に、sha256-、sha384-、sha512- のいずれかで始まり、その後にBase64文字が続くハッシュ指定が1つ以上含まれることが条件です。空の値や未対応アルゴリズムだけの値は、仕様上検証が行われないため「SRIなし」と数えます。ハッシュ値そのものが実ファイルと一致するかは、追加の取得を行わないため確認しません。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| 対象外(na) | 外部JavaScriptが0件 | 採点の分母から除外 |
| ○ 問題なし(pass) | すべての外部JavaScriptに有効なSRIがある | 重み2を満点で加算 |
| △ 要確認(warn) | 有効なSRIのない外部JavaScriptが1件以上ある | 重み2×0.45 |
- 根拠欄には「SRIなし: 未設定件数/外部JavaScript件数」を表示します。
- ASVS 5.0.0 V3.6.1はL3要件であり、動的スクリプトのようにSRIを適用できない正当な理由がありうるため、×(fail)ではなく△としています。
- 重大度はmedium、重みは2です。
自治体サイトでの判定例
| 外部JavaScriptの状態 | 判定 |
|---|---|
CDNのjQuery 1件に integrity="sha384-..." crossorigin="anonymous" | ○ |
| gtag.jsとタグマネージャーのみ(SRIなし) | △(SRI適用は困難。配信元の限定と台帳管理で補う) |
integrity="" が付いたCDNライブラリ | △(空の値は検証されない) |
| 外部スクリプトなし | 対象外 |
検出の限界と読み取り方
- タグマネージャーなどが実行時に追加するスクリプトは対象外です。動的に追加されたスクリプトにもSRIを付けることは技術的には可能ですが、HTMLからは確認できません。
integrityの値が正しい形式でも、ハッシュが実ファイルと一致しない場合は、ブラウザがスクリプトを実行しません。この場合、診断上は○でも、サイトの機能が止まっています。導入後は必ずブラウザで動作を確認してください。- 引用符で囲んだ
integrityの値は、2番目以降のハッシュ指定も見ます。integrity="md5-... sha384-..."のように未対応の指定が先にあっても、ブラウザと同じくsha384を有効なSRIと認めます。引用符なしの値は、先頭がSHA-2の指定である場合だけ有効とします。 - Chrome 141で導入された署名ベースの完全性検証(
integrity="ed25519-...")だけを指定した場合も「SRIなし」と数えます。対応ブラウザが限られるため、SHA-2のハッシュ指定との併記を推奨します。 crossorigin属性の有無は判定に含めていません。SRIとCORSの組み合わせは後述の注意点を参照してください。- △の内訳が「SRIを付けられる版固定ライブラリ」なのか「動的スクリプト」なのかで、対応方法が異なります。根拠欄の件数と、HTML上の該当スクリプトを照らし合わせて判断します。
外部スクリプトの種類別の対応目安
| 外部スクリプトの種類 | 推奨対応 | この項目の結果 |
|---|---|---|
| CDNの版固定ライブラリ | SRI+crossorigin、または自己ホスト | 対応すれば○に寄与 |
| 版指定なしのCDNライブラリ | 版を固定してからSRI、または自己ホスト | 対応すれば○に寄与 |
| アクセス解析・タグマネージャー | 台帳管理、CSPで配信元限定、不要なら削除 | △が残る(許容しうる) |
| チャットボット・地図・SNS | iframe埋め込み方式を優先、必要ページに限定 | iframe化すれば対象外になる |
外部JavaScriptにSRIがないとどんなリスクがあるか
- 配信元の改ざんによる悪性コード実行:CDNや外部サーバーのファイルが改ざんされると、自治体サイトを閲覧したすべての利用者のブラウザで悪性コードが動きます。フォームの入力内容の窃取、偽ログイン画面の表示、悪性サイトへの転送などが起こりえます。
- ドメインの所有者変更:2024年6月に報告されたpolyfill.ioの事例では、ドメインと配信サービスを取得した第三者が配信内容を改変し、このスクリプトを埋め込んでいた10万を超えるサイトで、モバイル端末の利用者が無関係な外部サイトへ転送されました。なお、このサービスは利用者のブラウザに応じて内容が変わる配信であったためSRIは適用できず、自己ホストや利用停止が対策になる事例でもあります。
- 改ざんの気づきにくさ:外部ファイルの変更は自治体側の更新履歴に残らず、利用者からの通報まで気づかないことがあります。
外部JavaScriptにSRIを設定する方法(ハッシュ生成・HTML・Next.js)
1. ハッシュ値の作成
# 版固定のファイルを取得してSHA-384のSRI値を作る
curl -s https://cdn.example.net/lib/1.2.3/lib.min.js \
| openssl dgst -sha384 -binary | openssl base64 -A
# 出力値の先頭に "sha384-" を付けて integrity 属性へ記入
ライブラリの公式配布ページやCDNがSRI値を併記している場合は、取得したファイルから自分で計算した値と一致することを確認してから使います。
2. HTMLへの記述
<script src="https://cdn.example.net/lib/1.2.3/lib.min.js"
integrity="sha384-..." crossorigin="anonymous" defer></script>
CMSのテンプレートで共通読み込みしている場合は、テンプレート側を修正します。
3. ビルドツールでの自動付与(Next.js等)
Next.jsでは next.config.js の experimental.sri(algorithm: "sha256" 等)でビルド時に自サイトのチャンクへSRIを付与する機能が提供されています(実験的機能のため、利用するバージョンのドキュメントで可否を確認してください)。外部CDNのスクリプトには、上記の手順で個別に付与します。
4. SRIを付けられない動的スクリプトへの対応
- 目的と担当課を台帳に記録し、不要なものは削除する
- CSPの
script-srcで配信元を具体的なオリジンに限定する - チャットボット等は親ページにスクリプトを入れず、iframe埋め込み方式を優先する
- 可能なライブラリは版を固定して自己ホストする(自己ホストならSRIは必須ではなくなる)
5. 段階的な導入手順
- トップページと主要テンプレートの外部スクリプトを一覧化し、「版固定ライブラリ」「版指定なしライブラリ」「動的スクリプト」に分類する
- 版指定なしのものは、現在配信されている版を確認してURLを版固定に変更する(この時点では動作が変わらないことを確認)
- 検証環境で
integrityとcrossoriginを付与し、PC・スマートフォンの主要ブラウザで、メニュー・検索・文字サイズ変更・読み上げなどの機能を確認する - 本番に反映し、ブラウザのコンソールにintegrityやCORSのエラーがないことを確認する
- ライブラリの更新手順書に「SRI値の再計算と差し替え」を追加し、CMS保守事業者にも共有する
- 動的スクリプトは台帳に「SRI適用不可の理由」と補完策(CSP、iframe化、契約)を記録する。ASVS 5.0.0 V3.6.1の趣旨からも、適用できない資産について判断の根拠を残しておくことが望まれます
6. 確認方法
# 外部スクリプトとintegrity属性の有無を確認
curl -s https://www.city.example.lg.jp/ | grep -o -i -E '<script[^>]*src="(https?:)?//[^>]*>'
ブラウザでページを開き、開発者ツールのコンソールに「integrity」に関するエラー(ハッシュ不一致やCORSエラー)が出ていないことを確認します。その後セキュリティAIチェッカーで再診断し、根拠欄の「SRIなし」の件数が減ったことを確認してください。
サイトを壊さないための注意点
- ハッシュが1文字でも違うとスクリプトが実行されず、メニューや検索などの機能が止まります。ライブラリを更新したら必ずintegrityも更新してください。
crossoriginを付けずにintegrityだけ付けると、別オリジンのスクリプトは読み込みに失敗します。- 版指定なし・
latestのURLにSRIを付けると、提供元の更新時に突然動かなくなります。先に版を固定してください。
よくある質問(FAQ)
SRIのハッシュはどうやって作りますか?
版固定のファイルを取得し、openssl dgst -sha384 -binary の出力を openssl base64 -A でBase64にした値の先頭に「sha384-」を付けます。CDNが併記している値を使う場合も、自分で計算した値と一致することを確認してから使います。
integrity属性を付けたのにスクリプトが読み込まれません。なぜですか?
crossorigin 属性がない、配信元が Access-Control-Allow-Origin を返していない、またはハッシュが実ファイルと一致していないことが考えられます。W3C SRI仕様はCORSなしでSRIを使うのは論理的な誤りとしています。
Googleアナリティクスやタグマネージャーにも SRI を付けるべきですか?
提供元が随時更新する動的スクリプトには、通常SRIを付けられません。台帳管理、CSPでの配信元限定、不要なタグの削除、iframe化などで補います。
integrity に MD5 や SHA-1 を使ってもよいですか?
使えません。仕様が求めるのはSHA-256・SHA-384・SHA-512で、それ以外のアルゴリズムだけを書いた場合は integrity がないのと同じ扱いになり、検証されません。
同じサイトから配信するJavaScriptにもSRIは必要ですか?
必須ではありません。この項目は外部オリジンのスクリプトだけを対象とし、外部JavaScriptが0件なら対象外になります。
ed25519 の integrity だけを書いた場合はどう判定されますか?
Chrome 141で導入された署名ベースの完全性検証(integrity="ed25519-…")だけの指定は「SRIなし」と数えます。対応ブラウザが限られるため、SHA-2のハッシュ指定との併記を推奨します。
この項目を含む127項目を、URLを入れるだけで無料診断します。