Skip to main content

Polyfillのサプライチェーン攻撃、JavaScript CDNアセットにマルウェアを埋め込む

著者

2024年6月26日

0 分で読めます

Uncovering the Polyfill.io Supply Chain Attack

2024年6月25日、Sansecのセキュリティ調査・マルウェアチームは、人気のJavaScript polyfillプロジェクトが中国発の企業と特定された外国の組織に乗っ取られ、CDNソース cdn.polyfill.io から取得されるJavaScriptアセットに悪意のあるコードが埋め込まれたと発表しました。Sansecによると、このpolyfill攻撃の影響を受けたWebサイトは10万件を超え、Intuitなどの上場企業も含まれています。

よくある質問

SnykはPolyfillのサプライチェーン攻撃の影響を受けていますか?

いいえ。ツールを含むSnykプラットフォームは、現在発生しているPolyfillのサプライチェーン攻撃の影響を受けていません。

SnykはPolyfillのセキュリティ問題を検出できますか?

リアルタイムかつ機械学習ベースのSASTエンジンであるSnyk Codeは、JavaScript、PHPをはじめとするさまざまなプログラミング言語で書かれたコード内の、多様なURLの使用を検出できます。

追加できるSnyk Codeのカスタムルールの例を紹介します。

custom_rules:
  - id: Polyfill supply chain compromise
    description: >-
      The polyfill.js is a popular open source library to support older
      browsers. This domain was caught injecting malware on mobile devices via
      any site that embeds cdn.polyfill.io.
    severity: high
    cwe:
      - CWE-506
    fix_analysis: Use alternatives provided at https://cdnjs.cloudflare.com/polyfill
    rule_code: >-
      StringLiteral<~".*http(s)?://((cdn\.)?polyfill\.io).*">
    languages:
      - html
      - javascript
      - php
      - java

このルールを使うと、JavaScriptまたはPHPコード内で使用されている cdn.polyfill.io のURLをすべて検出できます。たとえば、次のコードスニペットでは、手動でスクリプトを読み込んでいる箇所が検出されます。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Load Polyfill</title>
</head>
<body>
    <script>
        // Load the polyfill for Array.prototype.includes from cdn.polyfill.io
        (function() {
            var script = document.createElement('script');
            script.src = "https://cdn.polyfill.io/v3/polyfill.min.js?features=Array.prototype.includes";
            script.onload = function() {
                // Polyfill is loaded, you can use Array.prototype.includes safely now
                console.log([1, 2, 3].includes(2)); // Should log 'true'
            };
            document.head.appendChild(script);
        })();
    </script>
</body>
</html>

注: このカスタムルールはJavaScriptまたはPHPコードのみを対象とし、HTML内のプレーンな <script src=“…”></script> タグは検出しません。

cdn.polyfill.ioのウェブサイトに対する拒否リストルールだけを追加すればよいですか?

悪意のある攻撃者によって、新たなドメインが追加されたという報告が数多くあります。報告されているドメインには、polyfill[.]site、polyfill[.]com、bootcdn[.]net、bootcss[.]com、staticfile[.]net、staticfile[.]org、unionadjs[.]com、xhsbpza[.]com、union.macoms[.]la、newcrbpc[.]comなどがあります。こうした報告を注意深く監視し、それに応じてSnyk Codeのカスタムルールを更新することを強くおすすめします。

悪意のあるpolyfillライブラリでは何が起きたのですか?

2024年2月、中国企業が、Node.js polyfill-libraryの開発者Jake ChampionとWebサイト所有者からpolyfill.ioのWebサイトを買収すると発表しました。CDNとホスティングサービスを提供する中国企業Funnullが買収に乗り出し、それ以降、ドメインとGitHubの組織およびリポジトリを所有しています。

「Polyfill買収のお知らせ」という見出しと、FunnellによるPolyfill買収についての文章が表示されたFunnellのWebページ。

買収発表から間もなく、polyfill.ioドメインに polyfill.io.bsclink.cn への新しいCNAMEが設定されました。

この後に起こる惨事の兆候は、開発者コミュニティでも見られました。たとえば、Renaud Chaputによる次のGitHubコメントです。

Polyfill.ioはFinancial Timesのウェブチームが所有していましたが、その後コミュニティ管理に移行し、最後のメンテナーがこのプロジェクトを中国の怪しげなCDN企業に売却しました。同社はFastly(このサービスのOSSコードを実行するCDN/エッジコンピューティングプラットフォーム)から移行させ、配信されるファイルに手を加え始めました。

Renaud Chaput

不正行為を示すさらなる兆候は、4月から6月にかけてもコミュニティのユーザーから寄せられました。所有権が第三者企業に移ったことへの懸念が表明され、GitHubのIssueでコメントが削除されたことで、疑いはいっそう強まりました。

polyfill.ioの所有権が中国の第三者企業に移転したことを示す不審な兆候。その企業は後に、JavaScriptポリフィルライブラリ向けのマルウェアコードを配布したとして告発された

この件に関連して、FastlyでJake Championの同僚だったAndrew Bettsは、元々polyfill Webサービスを作成した人物です。このプロジェクトでは、ユーザーエージェントやその他の属性に基づき、JavaScript polyfillライブラリをWebサイトに自動で挿入できました。Andrewの発言をたどると、2月に、公式のcdn.polyfill.io Webサイトには関与していないと警告していたことが分かります。

この特定の攻撃者による悪意あるコードの挿入に関与していると判明したpolyfillライブラリは、npm上にはありません。ただし、Magentoなどのコンテンツ管理システムを含むさまざまなソフトウェアエコシステムのライブラリに、cdn.polyfill.ioから取得したJavaScriptコードを静的にインポートするコードが含まれている可能性があります。特に、Pythonプロジェクト向けにAPIドキュメントを生成するPyPIレジストリのpdocライブラリについて、セキュリティレポートCVE-2024-38526を確認しています。pdoc --mathコマンドでドキュメントを生成すると、polyfill.io上のJavaScriptファイルへのリンクが含まれる場合があります。pdocライブラリのこの動作はpdocバージョン14.5.1で修正されているため、できるだけ早くアップグレードすることを強くお勧めします。

polyfill.io Webサイトの現状はどうなっていますか?

polyfill.ioのWebサイトは現在、実質的にオフラインです。エンドユーザーを保護するため、uBlockなどの広告ブロック用ブラウザー拡張機能もpolyfill.ioのWebサイトに関する報告に対応し、ユーザーの安全を守るためにアクセスを積極的にブロックしています。

uBlockフィルター

6月21日、Google AdsアプリケーションのWebサイトに「侵害されたWebサイト」というエラーメッセージが表示されるようになったと報じられました。これは、googie-anaiytics[.]comドメインのWebサイトになりすました攻撃の報告を受けたことによるものです。

polyfill.ioのマルウェアによる影響は何ですか?

2017年、Fastlyでホストされていたpolyfill.io Webサイトの元開発者Andrew Bettsは、1日あたり9,100万件ものブラウザーがライブラリをインポートするリクエストを送信し、古いブラウザーを最新のWeb標準に対応させるためのリクエストが月間最大7億件に達したと報告しました。

毎日9,100万のブラウザーが、ウェブの最新機能に自動でアップグレードされています。

ソーシャルメディアなどの情報によると、Huluの企業Webサイトは、悪意のあるものと判明した cdn.polyfill.io WebサイトからJavaScriptライブラリを読み込んでいます(Theoによる報告)。

Huluのウェブサイトが、悪意のあるJavaScriptライブラリのコードをcdn.polyfill.ioから読み込んでいる

Germán Fernándezによる別の報告では、AtlassianのコミュニティWebサイトも、悪意のあるpolyfill.ioドメインからJavaScript polyfillライブラリをインポートしていることが確認されています。

Atlassianのコミュニティサイトは、マルウェアの注入が報告されているドメインpolyfill.ioからJavaScriptソースコードをバンドルしています。

Silent Push Labsは、政府機関のWebサイトにも悪意のあるpolyfill.ioのソースが含まれていることを確認し、CISAに報告しました。

JavaScript polyfillとは何ですか?

JavaScript Polyfillは、一般に、機能をネイティブにサポートしていない古いブラウザーで最新の機能を利用できるようにするために作られたコードです。従来、polyfillは、さまざまなバージョンのブラウザーでシームレスに動作するアプリケーションを開発するうえで不可欠でした。古いブラウザーで新しいJavaScript機能を実行できるようにする橋渡しの役割を果たし、ブラウザーの新しさや機能にかかわらず、一貫したユーザー体験を実現します。

Web開発の初期には、ブラウザーごとに進化のペースが異なり、同じコードでもプラットフォームによって動作が異なる断片化した環境になっていました。一般に、ブラウザーAPIのサポート状況は一様ではありませんでした。エンドユーザーが使用するブラウザーのバージョンを制御できないため、JavaScriptコードの実行時に同じAPIが利用できるとは開発者には保証できませんでした。こうした問題を解決するためにpolyfillライブラリが登場し、互換性を気にせず最新のJavaScriptコードを書けるようになりました。たとえば、Array.prototype.includesやPromiseなどの機能は、Internet Explorerのような古いブラウザーではサポートされていませんでした。それでも、ブラウザーでpolyfillライブラリを読み込めば、これらの機能を利用できました。

polyfillライブラリにおけるJavaScript CDNの役割

コンテンツデリバリーネットワーク(CDN)は、世界各地に配置・分散されたサーバーのネットワークで、ユーザーの地理的位置に応じてWebコンテンツを配信します。JavaScript polyfillライブラリでは、CDNがライブラリをホストし、世界中に効率よく配信する重要な役割を担います。CDNを活用することで、polyfillをユーザーにすばやく確実に届け、遅延を抑えて読み込み時間を短縮できます。また、CDNを使えば、JavaScriptライブラリをバンドルする必要がなくなるため、開発者にも便利です。

よくあるCDNの利用例として、Google Analyticsのようなクラウドベースの指標・アプリケーションパフォーマンス計測があります。Google Analyticsでは、次のコードをWebサイトに追加することを公式に推奨しています。

<script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>
<amp-analytics type="gtag" data-credentials="include">
<script type="application/json">
{
  "vars" : {
    "gtag_id": "<GA_MEASUREMENT_ID>",
    "config" : {
      "<GA_MEASUREMENT_ID>": { "groups": "default" }
    }
  }
}
</script>
</amp-analytics>

悪意のあるpolyfillの乗っ取りでは、cdn.polyfill.ioは広く使われていたCDNで、受信したリクエストのHTTPヘッダーに基づいてpolyfillを動的に配信していました。これにより、ユーザーのブラウザーとバージョンに応じた適切なpolyfillが配信され、最適な互換性が確保されていました。

CDNでホストされるpolyfillのセキュリティリスク

CDNでホストされるpolyfillを使用すると、アプリケーションのコンテキスト内で任意のJavaScriptコードが実行される可能性があるため、重大なセキュリティリスクが生じます。このリスクは、多くの場合、Webアプリケーションのクロスサイトスクリプティング(XSS)脆弱性として報告されます。

CDNからpolyfillライブラリを取得すると、アプリケーションは外部サーバー、つまりCDNソースそのものの完全性とセキュリティに依存することになります。最近のcdn.polyfill.ioへの攻撃のように、CDNやホストされたライブラリが侵害されると、新たに仕込まれたコードがユーザーのブラウザーに注入され、実行される可能性があります。悪意のあるコードは、ユーザーをフィッシングサイトにリダイレクトしたり、機密情報を盗んだり、さらなるマルウェアの拡散を引き起こしたりするなど、さまざまな不正行為を実行できます。ブラウザーセキュリティの観点では、この種のXSS脆弱性は最も深刻な影響をもたらします。

CDNのサプライチェーン攻撃から保護する

最近のJavaScript polyfillプロジェクトへの攻撃は、Webエコシステム全体を支えるリソースの重要性を浮き彫りにしました。CDNもその重要な一部です。サプライチェーンセキュリティの懸念は、PyPIやnpmなどのオープンソースパッケージレジストリを中心に語られることが多いものの、JavaScript polyfillへの攻撃は、CDNもWebを支える重要な基盤であることを改めて示しました。

このような攻撃から保護するために、次のベストプラクティスを検討してください。

  • 信頼できるCDNを使う: 評判の良いプロバイダーのCDNのみを使用してください。たとえば、Cloudflareは堅牢なセキュリティ対策と信頼性で知られています。

  • polyfillの代替を利用する: Cloudflareは、https://cdnjs.cloudflare.com/polyfill にpolyfillの代替を用意しており、置き換えて使うことを推奨しています。

  • 依存関係を監視する: すべてのサードパーティスクリプトと依存関係を定期的に監査・監視してください。

  • サブリソース完全性: Subresource Integrity(SRI)などのツールを使うと、CDNから配信されるコンテンツが改ざんされていないことを確認できます。また、監査済みで悪意のある動作や望ましくない動作がないと確認された、想定バージョンやハッシュに固定できます。

  • コンテンツセキュリティポリシー(CSP): 強固なCSPを導入し、スクリプトの読み込み元を制限してください。これにより、悪意のあるスクリプトの実行を防げます。polyfillはアプリケーションの読み込みにおけるクリティカルパスに含まれることが多く、ページ上の他のJavaScriptと同じ権限で実行されるため、この信頼関係を悪用しようとする攻撃者にとって格好の標的となります。このリスクは、安全で評判の良いCDNの利用、コンテンツセキュリティポリシー(CSP)などの堅牢なセキュリティ対策の導入、サードパーティ依存関係の定期的な監査が、こうした脆弱性から守るうえで重要であることを示しています。

  • 定期的に更新する: すべてのライブラリと依存関係を最新の状態に保ってください。多くの攻撃は、後のバージョンで修正済みの既知の脆弱性を悪用します。

  • 代替策を検討する: プロジェクトでpolyfillがまだ必要かどうかを評価してください。ブラウザーの進化に伴い、polyfillが提供していた機能の多くは現在、ネイティブでサポートされています。CDNなどのサードパーティプロバイダーに依存するのではなく、依存関係を自分のプロジェクトアセットに取り込むことを強くお勧めします。