Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】I uploaded a green square to a Next.js store and got stored XSS

2026年09月26日に「Dev.to」が公開したITニュース「I uploaded a green square to a Next.js store and got stored XSS」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Next.jsアプリの画像アップロード機能でStored XSSの脆弱性が見つかった。悪意あるスクリプトを埋め込んだSVG画像をアップロードすると、その画像を見た全ユーザーのブラウザでスクリプトが実行される。サーバーがファイル内容を検証せず、危険な形式でSVGを表示したのが原因だ。厳格なファイル検証と安全な表示が重要だ。

ITニュース解説

現代のWebアプリケーションにおいて、セキュリティは最も重要な要素の一つである。特に、ユーザーがファイルをアップロードできる機能を持つアプリケーションでは、細心の注意を払わなければ、深刻なセキュリティ上の問題を引き起こす可能性がある。今回取り上げるニュース記事は、Next.jsで構築されたあるオンラインストアの事例を通して、いわゆる「Stored XSS(格納型クロスサイトスクリプティング)」と呼ばれる脆弱性がどのように発生し、悪用されるのか、そしてそれを防ぐための具体的な方法について詳しく解説している。システムエンジニアを目指す上で、このような実例から学ぶことは非常に有益である。

まず、XSSとは「Cross-Site Scripting(クロスサイトスクリプティング)」の略で、Webサイトに悪意のあるスクリプト(JavaScriptコードなど)が埋め込まれ、それを閲覧したユーザーのブラウザ上で実行されてしまう脆弱性のことを指す。Stored XSSは、攻撃者が埋め込んだスクリプトがWebサーバーに保存され、そのコンテンツを閲覧するすべてのユーザーに影響を及ぼす点が特徴である。この場合、Webサイトの正規のコンテンツとして悪意のあるスクリプトが提供されるため、ユーザーはフィッシング詐欺や情報漏洩などの被害に遭う危険性がある。

今回の事例では、「OopsSec Store」という架空のNext.jsストアが対象となっている。このストアの管理画面には、商品を登録・編集する際に、その商品のイメージ画像をアップロードする機能があった。ここで問題となったのは、アップロード可能な画像形式の中に「SVG(Scalable Vector Graphics)」が含まれていた点である。SVGファイルは、XMLというテキストベースの形式で記述される画像ファイルであり、画像データだけでなく、HTMLと同様にJavaScriptコードを埋め込むことが可能である。この特性が悪用されることになった。

攻撃者は、まずこのストアの管理者アカウントへのアクセス権限を取得する必要がある。記事では、SQLインジェクションによって管理者のパスワードハッシュを抜き出すか、または弱いMD5ハッシュのパスワードをクラックするといった方法が示唆されている。これは、本質的なXSS脆弱性とは異なるが、XSS攻撃を実行するための「前提条件」として、システムに別の脆弱性が存在する場合があることを示している。セキュリティは様々な要素が複雑に絡み合って成立するものであり、一つの脆弱性が別の脆弱性の足がかりとなることも少なくない。

管理者アカウントでログインした後、攻撃者は悪意のあるSVGファイルを作成する。具体的には、見た目は普通の緑色の四角い画像だが、そのXMLコードの中に「<script>alert('XSS executed!');</script>」というJavaScriptコードを埋め込んだSVGファイルを用意する。このスクリプトは、実行されると「XSS executed!」というメッセージボックスを表示するだけのシンプルなものだが、これは攻撃が成功したことを示す証拠となる。実際には、ユーザーのクッキーを盗み出したり、偽のログインフォームを表示させたりするなど、より悪質なスクリプトを埋め込むことが可能である。

この悪意のあるSVGファイルを、管理画面の商品画像アップロード機能を使って、実際の商品画像としてアップロードする。このとき、サーバー側でのファイルの検証方法に問題があった。サーバーは、アップロードされたファイルが正当な画像ファイルであるかを判断する際に、「Content-Type」ヘッダーという情報を信用していた。このヘッダーは、クライアント(Webブラウザなど)がサーバーにファイルを送信する際に、「これはimage/svg+xmlです」といった形でファイルの種類を伝えるもので、クライアント側で自由に設定できてしまう。サーバーは、このヘッダーが「image/svg+xml」であれば、その内容が本当にSVG画像であるかを深く検査せず、そのまま受け入れて保存してしまったのである。本来であれば、ファイルの中身を実際に読み込み、画像データとしての整合性や、予期せぬスクリプトが含まれていないかなどを確認すべきだった。

さらに、フロントエンド、つまりユーザーがWebサイトを閲覧する際に表示される画面の作り方にも問題があった。このストアでは、アップロードされたSVG画像を表示する際に、HTMLの「<object>」タグを使用していた。「<object>」タグは、埋め込まれたコンテンツを独立したドキュメントとして扱い、その中に含まれるスクリプトも実行してしまう性質がある。もし、スクリプトの実行をブロックする「<img>」タグを使用していれば、SVG画像は表示されても、埋め込まれたJavaScriptが実行されることはなかった。サーバーでの検証不足と、フロントエンドでの安全でないレンダリング方法、この二つの問題が重なることで、Stored XSS脆弱性が成立してしまったのである。

こうして悪意のあるSVGファイルがサーバーに保存されると、その商品ページを閲覧したすべてのユーザーのブラウザ上で、埋め込まれたJavaScriptが実行されてしまう。管理画面で商品プレビューを表示した際や、直接アップロードされたSVGファイルにアクセスした場合でも同様にスクリプトは実行される。

このような深刻な脆弱性に対する対策は、複数の層で実施されるべきである。 まず一つ目は、サーバー側でアップロードされたファイルの「Content-Type」ヘッダーを信用せず、実際のファイル内容を検査することだ。file-typeのようなライブラリを使用すれば、ファイルのバイナリデータを読み込んで、その種類を正確に判別できる。SVGファイルはスクリプト実行のリスクがあるため、もし本当にSVGを許可する必要がなければ、この段階でアップロードを拒否してしまうのが最も安全な方法である。

二つ目は、もしSVGファイルのアップロードをどうしても許可する必要がある場合、アップロードされたSVGの内容をサーバー側で「サニタイズ(無害化)」することだ。DOMPurifyのようなライブラリを使うことで、SVGファイルからJavaScriptのスクリプトタグやイベントハンドラーなど、悪意のある可能性のある要素を自動的に除去し、安全なSVG形式に変換してから保存できる。これにより、たとえ攻撃者がスクリプトを埋め込もうとしても、それがサーバーに保存される段階で取り除かれるため、実行されることはない。

そして三つ目は、アップロードされたファイルがWebブラウザに提供される際に、セキュリティ関連のHTTPヘッダーを設定することである。具体的には、「Content-Security-Policy(CSP)」ヘッダーを設定し、「script-src 'none'」と指定することで、そのレスポンス内でJavaScriptの実行を完全に禁止できる。また、「X-Content-Type-Options: nosniff」ヘッダーを追加することで、ブラウザがContent-Typeヘッダーを無視してコンテンツの種類を推測し、誤ってスクリプトとして実行してしまうことを防ぐ。これらのヘッダーは、たとえサーバーやサニタイズ処理をすり抜けて悪意のあるスクリプトが保存されてしまったとしても、ユーザーのブラウザでの実行を最終的に阻止する役割を果たす。

この記事は、Webアプリケーション開発において、ユーザーからの入力を決して信用せず、常に多層的な防御策を講じることの重要性を教えてくれる。システムエンジニアを目指す皆さんにとって、このような具体的な脆弱性のメカニズムと対策を理解することは、セキュアなシステムを設計・実装するための基礎力を養う上で不可欠な学びとなるだろう。

関連コンテンツ

関連IT用語

関連ITニュース