XSSとは?
XSS(クロスサイトスクリプティング)とは、Webアプリケーションの入力や出力処理に不備がある場合に、不正なスクリプトを実行される攻撃です。たとえば、input要素などでユーザーが入力した内容をそのままDOMやHTMLとして表示したり、サーバーからのレスポンスを適切にサニタイズせずにブラウザに出力すると、悪意のあるスクリプトが実行される可能性があります。
また、XSSはブラウザ上で動作するJavaScriptが原因となることも多いですが、サーバーサイドでもエスケープ処理やContent Security Policy(CSP)の適用などの対策が必要です。脆弱性診断ツールを利用することでXSSのリスクを軽減できますが、ツールに頼るだけでは不十分な場合もあります。開発段階でフロントエンドとバックエンド双方の基本的なセキュリティ対策を徹底することが重要です。
XSSは主に以下の原因で発生します。
・不適切なエスケープ:出力する際にHTMLやJavaScriptとして解釈される文字列を適切にエスケープしていない。
・入力値の検証不足:信頼できないデータをそのまま受け入れる。

XSSの脅威
XSS攻撃を受けると、以下のような被害が発生する可能性があります。
機密情報の漏洩
ユーザーのCookie(セッションID)やローカルストレージのデータを攻撃者のサーバーに送信し、機密情報を奪取します。これにより、攻撃者はユーザーアカウントへの不正アクセスが可能になります。
Webアプリケーションの改ざん
悪意のあるスクリプトによって、Webアプリケーションの内容を偽の情報やフィッシングページに改ざんされます。これにより、他のユーザーが誤った情報を信用したり、さらなる被害を受ける可能性があります。
意図しない操作
攻撃者がスクリプトを用いて、ユーザーに気づかれないように意図しない操作を実行させる場合があります(例:不正送金やデータ削除)。
なりすまし
セッションIDを奪取された場合、攻撃者がユーザーになりすましてログインし、権限のある操作(注文、データ改ざんなど)を実行します。
XSSの種類
XSSには大きく3つの種類があります。
反射型XSS(Reflected XSS)
反射型XSSは、攻撃者が作成した特定のURLをクリックした際に発生するXSSです。攻撃者がURLに悪意のあるスクリプトを含め、ユーザーがそれを開くことでスクリプトが実行されます。 例えば、以下のように検索窓で入力したパラメーターを検索結果画面に表示する仕様がある場合、スクリプトをパラメーターとして渡すことでXSSが発生します。
https://example.com/test?name=<script>alert(‘XSS’)</script>
蓄積型XSS(Stored XSS)
蓄積型XSSは、攻撃者が悪意のあるスクリプトをWebアプリケーションに保存し、そのスクリプトが他のユーザーによって実行されることで発生します。 例えば、コメント機能があるサイトで、攻撃者が以下のようなスクリプトをコメント欄に入力して保存した場合、他のユーザーがそのページを閲覧した際にスクリプトが実行されます。保存されたスクリプトは、永続的に影響を及ぼすため、「持続型XSS」とも呼ばれます。
<script>alert('XSS')</script>DOM-based XSS
DOM-based XSSは、他のXSSと異なり、サーバーを介さずクライアントサイド(ブラウザ内)で発生するXSSです。この攻撃では、ログに記録が残らない場合も多いため、検出が難しいとされています。 例えば、以下のようにJavaScriptでURLの#以降の文字列をそのままページ上に表示する仕様がある場合URLに#<script>alert(‘XSS’)</script>を追加してリンクを作成し、ユーザーを誘導することで、攻撃者のスクリプトがユーザーのブラウザ上で実行されます。DOM-based XSSは、JavaScriptによるクライアントサイドの処理が主な原因で発生します。
document.getElementById("output").innerHTML = location.hash.substring(1);XSSの対策方法
文字列のエスケープ処理
ユーザーが入力したデータをHTMLに出力する際に、特殊文字(<, >, &, ” など)をエスケープ処理する必要があります。 そうすることで<script>タグをそのまま表示させず<script>とすることでスクリプトが実行されるのを防ぎます。フロントエンドやサーバーサイドでエスケープを適切に実施することが重要です。
属性値の文字列をクオテーションで囲む
URLに含まれたクエリ文字列をHTMLの属性に反映するような仕様の場合はエスケープ処理だけで防ぐことができません。 クエリ文字列内のクオテーション(”)を"へエスケープ処理することでXSSを防ぐことができ、下記の様にクエリ文字列内にonmouseoverイベントを含めた場合でもただのvalue値とすることができます。
https://example.com/search?keyword=” onmouseover=’alert(1)’
<input value="" onmouseover=’alert(1)’" />リンクのURLのスキームをhttp/httpsに限定する
aタグのhref属性にもクエリ文字列のリンクを反映する仕様がある場合エスケープ処理やクオテーションを囲む方法でもXSSを防ぐことができません。なぜならhref属性にはhttp,httpsスキームだけでなくjavascriptスキームを指定することができるからです。なのでhttpやhttpsに限定することで、不正なJavaScriptスキーム(例:javascript:)による攻撃を防ぐことができます。
DOM操作用のメソッドやプロパティを使用する
DOM操作では、文字列をHTMLとして解釈するinnerHTMLを避け、テキストノードとして扱うtextContent等を使用することでXSSを防ぐことができます。
CookieにHttpOnly属性を付与する
ログインが必要なWebアプリケーションなどの場合Cookieを使用しているケースがあるかと思いますがなりすまし等を防ぐためにCookieの情報を盗み取られないようにする必要があります。 サーバーサイド側でCookieを発行する時に下記の様にHttpOnly属性を付与すればJavaScriptからCookieの値を取得することを出来なくすることができます。
Set-Cookie: sessionId=abcdefgh; HttpOnly
フレームワークをの機能を使った対策
モダンなフレームワーク(例:React, Angular, Vue.js)は、デフォルトでエスケープ処理が適切に実装されていますのでXSSを防ぐことができます。 ですがReactのdangerouslySetInnerHTMLというinnerHTMLに相当する機能を使用する場合はエスケープ処理が必要ですのであまり使わないことをおすすめします。また、JavaScriptスキームもデフォルトでは防ぐことができませんので対策が必要です。
ライブラリ(DOMPurify)を使った対策
XSS対策ライブラリのDOMPurifyのsanitize関数を使うことで危険な文字列を削除することが可能です。githubやnpmコマンドでインストールすることで使用することができます。
まとめ
XSS(クロスサイトスクリプティング)は、Webアプリケーションの脆弱性を悪用し、不正なスクリプトを実行させる攻撃です。反射型、蓄積型、DOMベース型の種類があり、機密情報の漏洩や意図しない操作を引き起こします。対策として、特殊文字のエスケープ、textContentの使用、HttpOnly属性の付与が効果的です。さらに、ReactやVue.jsなどのフレームワークやDOMPurifyなどのライブラリを活用することで、XSSリスクを大幅に軽減できますので被害にあわないよう対策していきましょう。
参考文献
Cross-site scripting (クロスサイトスクリプティング) – MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
攻撃の種類 – ウェブセキュリティ | MDN フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識
フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識