SRIメモ

polyfill.ioの事件を聞いて気になったのですが、下記のコードでライブラリを読み込む部分はの部分になるのですか?

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
    href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=Noto+Sans+JP:wght@300;400;500;700&display=swap"
    rel="stylesheet" />

はい!今回のコードでは、外部のライブラリ(正確にはWebフォントのCSS)を読み込んでいるのは、最後の <link rel="stylesheet"> の部分です。

ただし、<link> がすべて外部ライブラリを読み込んでいるわけではありません。それぞれ役割が異なります。

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />

<link
    href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=Noto+Sans+JP:wght@300;400;500;700&display=swap"
    rel="stylesheet" />
記述役割
rel="preconnect"外部サーバーへの接続を先回りして準備する。フォント自体は読み込まない
rel="stylesheet"指定したURLからCSSを読み込む。今回の場合はGoogle Fontsのフォント設定を取得する

つまり、今回のコードではGoogle Fontsを利用するために、外部サーバーからCSSとフォントファイルを取得しています。## Polyfill.ioの事件との違い

Polyfill.ioの事件で問題になったのは、主に次のような読み込み方です。

<script src="https://cdn.polyfill.io/v3/polyfill.min.js"></script>

これは外部サーバーからJavaScriptを取得して、自分のWebサイト上で実行する記述です。

2024年、Polyfill.ioのドメインが新しい所有者に渡った後、配信されるJavaScriptに悪意のあるコードが混入し、条件に合致した訪問者を別のサイトへ転送するなどの被害が報告されました。

ここが重要な違いです。

読み込み方法取得するもの主な役割
<script src="...">JavaScriptプログラムを実行する
<link rel="stylesheet">CSSデザイン・表示を設定する
<link rel="preconnect">接続準備通信を高速化する

今回の場合は?

今回のコードを見る限り、Google Fontsから取得しているのはフォント用のCSSとフォントファイルです。

Polyfill.ioのように、外部から取得したJavaScriptをそのまま実行する仕組みとは異なります。

ただし、外部サービスへの依存には変わりありません。

例えば、Google Fontsが利用できなくなれば、指定フォントが表示されず、代替フォントで表示される可能性があります。

また、外部サーバーへの通信に伴うプライバシー上の考慮も必要です。

私からのおすすめは、重要なアプリでは外部JavaScriptの読み込みを必要最小限にすることです。

特に次のような記述を見つけたら、提供元を確認するとよいです。

<script src="https://外部サイト/example.js"></script>

今回のようなGoogle Fontsの利用とは、セキュリティ上の性質が異なります。

こういう外部依存関係を一つずつ把握しておくと、将来的なサプライチェーン攻撃への備えにもなりますよ! 😊

ちなみにSRI ?ハッシュ値を利用してそのライブラリが改竄されていないかを確認する場合のコードはどのようになりますか?

これは SRI(Subresource Integrity:サブリソース完全性) という仕組みです。

HTMLにライブラリのハッシュ値を記述しておき、ブラウザが外部から取得したファイルのハッシュ値と照合します。

一致しなければ、そのファイルの読み込み・実行を拒否します。

1. JavaScriptライブラリの場合

例えば、外部サーバーからJavaScriptライブラリを読み込む場合は、次のように書きます。

<script
    src="https://cdn.example.com/library.min.js"
    integrity="sha384-ここにハッシュ値"
    crossorigin="anonymous">
</script>

追加した属性は2つです。

属性役割
integrityファイルの正しいハッシュ値を指定する
crossorigin="anonymous"外部サーバーからCORS対応で取得する

integrity に指定するハッシュ値は、SHA-256、SHA-384、SHA-512などが使えます。

実際には、SHA-384を使用する例がよく見られます。

2. CSSライブラリの場合

今回のようなCSSの読み込みにも利用できます。

<link
    rel="stylesheet"
    href="https://cdn.example.com/style.css"
    integrity="sha384-ここにハッシュ値"
    crossorigin="anonymous"
/>

このように、<script> だけでなく、<link rel="stylesheet"> にもSRIを設定できます。

3. ハッシュ値の作り方

macOSのターミナルでも、OpenSSLを使えば簡単に生成できます。

例えば、信頼できる配布元から取得した library.min.js がある場合、

openssl dgst -sha384 -binary library.min.js | openssl base64 -A

実行すると、次のようなBase64形式のハッシュ値が出力されます。

AbCdEf1234567890...

これをHTMLに設定するときは、先頭に sha384- を付けます。

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

※上記のハッシュ値は説明用のダミーです。実際には対象ファイルから生成した正しい値を設定してください。

このとき、注意したいことが3つあります。

  1. ハッシュ値は信頼できる配布元のファイルや公式に公開された値から用意する。
  2. ライブラリのバージョンを更新したら、ハッシュ値も再確認する。
  3. 外部サーバーがCORSに対応し、適切な Access-Control-Allow-Origin ヘッダーを返す必要がある。

特に1番目は重要です。改竄されたファイルをダウンロードして、そのファイルからハッシュ値を作ってしまったら意味がありません。MDN+1

4. Google Fontsについて

ここは少し注意が必要です。

今回のGoogle FontsのURLは、アクセスしてきたブラウザに応じて返すCSSの内容が変わる仕組みになっています。Google自身もこの仕様を説明しています。Google for Developers

そのため、あるブラウザで取得したCSSからSRIのハッシュ値を生成しても、別のブラウザでは一致しない可能性があります。

また、CSSにSRIを設定しても、そのCSSから別途取得するフォントファイル自体のハッシュ検証までは行われません。

したがって、現在のGoogle Fontsについては、無理にSRIを設定することはおすすめしません。

参考資料

詳しく確認できる公式資料はこちらです。

  • MDN:サブリソース完全性(SRI)
  • MDN:integrity属性
  • Google Fonts:技術的な考慮事項

私が特におすすめしたいのは、外部JavaScriptを利用するときは、SRI対応のCDNを選び、バージョン固定とハッシュ検証をセットで行うことです。

これだけでも、外部ライブラリの供給元が改竄された場合に備える有効な防御策になりますよ! 😊

タイトルとURLをコピーしました