本文へスキップ
AI Web制作・LP

WebサイトのSRI設定方法|外部スクリプトのハッシュ検証と更新手順

固定版の外部JavaScript・CSSをSRIで確認し、更新時に再検証する方法

CDNからJavaScriptやCSSを読み込むときは、HTMLのintegrity属性に、確認済みの配信ファイルから作った暗号学的ハッシュを指定します。ブラウザーは取得したファイルの内容をその値と照合し、一致しなければ読み込みを拒否します。導入時は、固定版のファイルを確認してSHA-384を生成し、クロスオリジン配信のCORS応答を確かめてから、URLとハッシュを同じ変更として反映します。

先に答えると、SRIは「承認したファイルと配信時のファイルが同じか」を確認する仕組みです。まず提供元とバージョンを確認できる固定ファイルを選び、そのファイルのハッシュを生成します。HTMLのintegrityへ設定し、別オリジンの場合はcrossorigin="anonymous"とCDNのCORS応答も確認します。正規更新では、更新元を確認してからハッシュを再計算し、ファイルとHTMLを一緒にリリースします。最新URLを取得してその場でハッシュを付けるだけでは、取得時点ですでに改ざんされていたファイルを承認してしまう可能性があります。

SRIを設定する5段階。固定版を選ぶ、実ファイルを確認、ハッシュを生成、CORSを確認、更新時に再検証の順に進める。
固定版を選ぶ → 実ファイルを確認 → ハッシュを生成 → CORSを確認 → 更新時に再検証、の順で確認します。ハッシュの出所と更新承認も記録します。
  1. 提供元とバージョンを確認できる固定版を選ぶ。
  2. 承認済みの配布物と、CDNが返す対象ファイルを照合する。
  3. 確認したファイルからSHA-384ハッシュを生成する。
  4. クロスオリジン応答のCORS設定を確認し、実ブラウザーでも読み込む。
  5. 更新のたびに出所・ファイル・ハッシュ・HTMLを再確認する。

本記事のポイント

  1. SRIは固定したファイルの取得内容をハッシュ照合し、一致しないリソースの読み込みを拒否する。
  2. クロスオリジンでSRIを使うときは、crossorigin属性と配信元のCORS応答を両方確認する。
  3. 正規の更新時は提供元を確認した実ファイル、ハッシュ、HTMLを同じ変更単位で検証する。

SRIを設定する5段階。固定版を選ぶ、実ファイルを確認、ハッシュを生成、CORSを確認、更新時に再検証の順に進める。
固定版を選ぶ → 実ファイルを確認 → ハッシュを生成 → CORSを確認 → 更新時に再検証、の順で確認します。ハッシュの出所と更新承認も記録します。

SRIで検証できる範囲を先に決める

Subresource Integrity(SRI)は、HTMLが指定したリソースについて、ブラウザーが取得した内容のハッシュをintegrityの値と比較する仕組みです。対象ファイルの内容が期待値と一致すれば読み込みを続け、一致する値がなければブラウザーはスクリプトを実行せず、スタイルシートを適用しません。ハッシュはファイル内容の一致を検査するための値であり、提供元、リリース番号、承認者を自動で証明するものではありません。

導入範囲を調べるときは、タグの数を数えるだけでなく、外部依存の所有者・目的・変更窓口も把握しておくと、更新承認の経路が明確になります。サイトに置かれた計測タグやチャットなどの棚卸しは、企業サイトの外部スクリプト棚卸しで扱う全体管理の対象です。本記事では、そのうち固定版のJavaScript・CSSをHTMLから読み込む箇所に絞り、ハッシュの確認と更新に焦点を当てます。

SRIが守るのは、指定した一つのリソースと期待ハッシュの一致です。HTMLそのものを書き換えられたり、攻撃者がHTMLとハッシュの両方を変えたりすれば、この照合だけでは防げません。また、ハッシュが一致しても、そのコードが良質か、送信データや副作用が適切かまでは判断しません。最初のハッシュを承認する前に、正規のリリース情報、配布元、変更内容を確認することが前提です。ページと通信先の許可方針を定めるCSPとも役割が異なり、SRIは許可された取得元の安全性を代替する仕組みではありません。

固定版の配信ファイルからSHA-384を作る

最初に、更新で内容が入れ替わるlatestや無指定のURLではなく、バージョンを特定できるURLを選びます。提供元のリリースノートと配布経路を確認し、社内の依存関係一覧や変更記録にパッケージ名、バージョン、URL、取得日、確認者を残します。更新前後で同じURLの内容が変わる運用なら、そのURLをSRI対象として固定する意味が薄くなるため、版ごとに変わるURLや、承認済みの社内配布物を使えるか検討します。

ハッシュを計算するのは、信頼できる更新元を確認して凍結したファイルです。公開CDNから現在の内容を取得し、同じ取得元の内容だけを根拠にハッシュを承認するやり方は避けます。たとえば、提供元の正式リリースまたは承認済みのパッケージ保管先からexample-3.2.1.min.jsを取得し、署名・チェックサム・版番号や変更内容を確認します。実際にブラウザーへ返されるファイルと、手元の確認済みファイルが一致することも確かめます。配信時に別ファイルへ変換・差し替えを行うなら、ハッシュの対象とその工程を見直してください。

macOSやLinuxのOpenSSLでは、次のコマンドでファイルのSHA-384ダイジェストをBase64にし、SRIで使う接頭辞を付けられます。

printf 'sha384-%s\n' "$(openssl dgst -sha384 -binary ./vendor/example-3.2.1.min.js | openssl base64 -A)"

openssl dgst -sha384 -binaryがファイルからバイナリ形式のダイジェストを作り、openssl base64 -Aが改行なしのBase64文字列へ変換します。最後にsha384-を付けるので、出力全体をintegrity属性へ貼り付けられます。ファイル名は実際に検証した固定版へ置き換えてください。生成後は、コマンドを実行したファイルのパス、版、ハッシュ値を変更レビューに残し、別の作業者が同じファイルで再計算できる状態にします。

同じファイルを信頼できるビルド成果物とCDNからそれぞれ取得できるなら、両方を同じ手順で計算して値が一致することを確認します。差があれば、URLのリダイレクト、別バージョンの混在、CDN側の差し替え、取得元の取り違えなどを調べます。一致しない状態で、どちらかの値を選んで公開してはいけません。SRIの値は秘密情報ではありませんが、値を生成したファイルの由来と承認を記録しないと、後から意図した版か判断できません。

integrityとcrossoriginを設定してCORSを確認する

固定版のファイルとハッシュを確定したら、HTMLのURLとハッシュを同時に設定します。以下のダイジェスト部分は説明用の置き換え文字列です。実際には、直前の手順で確認したファイルから得た完全な値を使います。

<script src="https://cdn.example.com/lib/3.2.1/lib.min.js"
                integrity="sha384-BASE64_DIGEST"
                crossorigin="anonymous"></script>

        <link rel="stylesheet" href="https://cdn.example.com/lib/3.2.1/lib.min.css"
              integrity="sha384-BASE64_DIGEST"
              crossorigin="anonymous">

クロスオリジンのSRI対象にはCORSで取得できる応答が必要です。crossorigin="anonymous"は、ブラウザーにCORSを使って読み込むことを伝え、別オリジンへの資格情報送信を行わない形で要求します。CDN側は、アクセスを許可するAccess-Control-Allow-Origin応答ヘッダーを返す必要があります。公開ファイルであれば*が使われることがありますが、CDNの実際の応答とサイトの要件を確認してください。use-credentialsでは要求元オリジンをAccess-Control-Allow-Originに明記し(*は不可)、Access-Control-Allow-Credentials: trueも返す必要があります。公開ライブラリを読むだけなら、特別な理由がない限り資格情報を送らない設定から検討します。

確認は、公開ページと同じURLをブラウザーで読み、開発者ツールのNetworkで最終応答のステータス、リダイレクト後のURL、Access-Control-Allow-Originを見ます。たとえば次のGETで応答ヘッダーを調べられます。Originには実際の公開元を指定し、リダイレクトがあるときは最終ファイルのヘッダーを確認します。

curl -sS -L -D - -o /dev/null \
          -H 'Origin: https://www.example.jp' \
          'https://cdn.example.com/lib/3.2.1/lib.min.js'

このコマンドはヘッダーの確認材料にはなりますが、ブラウザーのCORS判定やSRI検証を代行しません。実際のサイトでスクリプトが読み込まれること、CSSが反映されること、コンソールやNetworkに拒否が出ないことも確かめます。CDNのキャッシュや地域別配信で内容・ヘッダーが変わる構成では、対象とする配信先・経路で同じ確認を行います。

更新時にハッシュを差し替え、失敗を切り分ける

ライブラリの新しい版が出たら、いきなりHTMLのハッシュだけを更新せず、まず変更元と更新理由を確認します。利用しているAPIや互換性、脆弱性修正の有無をリリース情報と照合し、組織が承認したファイルを固定します。そのファイルから新しいSHA-384を計算し、srcまたはhref、integrity、必要なcrossoriginを一つの変更単位で更新します。配信ファイルとHTMLの期待ハッシュを同じ変更単位で検証します。レビューでは旧版・新版のURLとハッシュを見比べ、意図しないURL変更や属性削除がないことを確認します。

リリース前は、テスト環境で対象ページを読み、コンソールのエラーだけでなく、重要なフォームやナビゲーション、計測など、そのファイルに依存する動作を確かめます。SRIは変更があれば正規の更新であっても旧ハッシュでは拒否するため、ファイルだけ先に公開したり、HTMLだけを先に変えたりすると利用者へ読み込み失敗が出る場合があります。CDNの反映とHTMLの公開順を調整し、問題が出たら承認済みの旧版へ戻せるよう、ファイルとHTMLの組を記録しておきます。Webページの更新責任者、承認者、公開後レビューを整理する考え方は、Webサイトのコンテンツガバナンスの記事で確認できます。外部ファイルの変更でも、誰が利用影響を確認し、いつ見直すかを決めておくと、更新忘れと無確認の差し替えを減らせます。

複数のハッシュを指定する場合も、単純に新旧の値を混ぜればよいわけではありません。複数のハッシュ関数があると、ブラウザーは指定された中で最も強い関数を選び、その強度のハッシュを照合します。異なる配信内容を許容するために複数値を使うなら、許容する各ファイルを個別に承認し、選択される最強アルゴリズムの値を揃えます。より強い関数の値が一致しないときに、弱い関数の値で自動的に救済される設計にはしないでください。SHA-384を使う標準的な一つの固定ファイルでは、通常は一つの値で足ります。

読み込み失敗は、CORSの失敗とハッシュ不一致を分けて調べます。CORSで拒否されているときは、ブラウザーがクロスオリジン応答を利用できる条件を満たしていません。Networkでリダイレクト先を含む応答とAccess-Control-Allow-Originを確認し、crossoriginの設定、CDNの許可元、資格情報の有無を見直します。ハッシュ不一致なら、CDNから応答はあっても、実ファイルの内容がHTMLの期待値と違います。手元の承認済みファイルでハッシュを再計算し、URL、バージョン、配信内容、HTMLの値を順に照合します。コンソールの文言だけで原因を決めず、取得の可否とハッシュの一致を別々に確認します。

どちらの失敗でも、対処のためにintegrityを外すと検査がなくなり、原因が隠れます。正規の更新が確認できないときは新しい値を採用せず、配信を一時停止するか、確認済みの版へ戻してから調査を続けます。Content-Security-Policy(CSP)は取得元・実行方針を管理する仕組みで、SRIとは別の制御です。違反を先に観測し、本番制限へ移す運用は、CSP Report-Onlyによる段階的な検証と組み合わせます。

よくある質問

SRIは何を確認し、何を保証しませんか?

HTMLに記したハッシュと、対象リソースの取得内容が一致するかを確認します。一致しないファイルの実行や適用をブラウザーが拒否します。一致したコードの安全性、配布元の正当性、HTML自体の改ざん、コードが送るデータまでは保証しません。ハッシュを登録する前に配布元と版を確認してください。

SHA-384をどうやってintegrityの形式にしますか?

承認済みの固定版ファイルに対し、OpenSSLのSHA-384ダイジェストをバイナリ出力し、Base64に変換して、先頭へsha384-を付けます。本文のコマンドはこの形式を一度に出力します。ライブラリのバージョンが変われば、ファイルを再確認して値を再計算します。

クロスオリジンのCDNでcrossorigin属性が必要なのはなぜですか?

SRIを使ったクロスオリジン取得では、CORSを通して応答を利用できる必要があるためです。公開CDNを読む場合はcrossorigin="anonymous"を設定し、CDN応答にサイトが許可されていることを示すAccess-Control-Allow-Originがあるか確認します。属性だけ、またはヘッダーだけでは条件を満たしません。

CORSエラーとハッシュ不一致はどこが違いますか?

CORSエラーは応答を読み込む条件の失敗、ハッシュ不一致は取得した内容が期待値と違う状態です。NetworkでURL・リダイレクト・CORS応答ヘッダーを確認してから、承認済みファイルの再計算値とHTMLを照合します。どちらもブラウザー上は読み込み失敗として見えることがあるため、メッセージだけでなく応答ヘッダーとファイルの値を分けて調べます。

関連ページと関連記事

Webサイトの外部依存を継続管理する

外部JavaScriptやCSSの更新責任や確認手順を、Webサイトの運用体制に合わせて整理したい場合は、ファネルAiへご相談ください。運用・改善で困っている点をお聞かせいただければ、状況に応じた進め方をご提案します。お問い合わせはこちら。

仕様・実装を確認できる公式資料

メディア一覧へ戻る