【セキュリティ担当者必見】XSS対策ガイド:基本知識から実践的なテスト方法までわかりやすく解説

この記事について

クロスサイトスクリプティング(XSS)は、Webアプリケーションの代表的な脆弱性の一つであり、個人情報の盗難やマルウェアの感染などが引き起こされる可能性があります。この記事では、多くの具体例をあげながらXSSの仕組みや対策についてわかりやすく解説します。Webアプリケーションのセキュリティ向上のために、ぜひ参考にしてください。

目次

クロスサイトスクリプティング(XSS)とは

クロスサイトスクリプティング(Cross Site Scripting;XSS)とは、攻撃者が悪意のあるスクリプト(JavaScriptなどで書かれたプログラム)をWebサイトに注入することで、そのWebサイトに訪れた他のユーザーのブラウザ上でスクリプトが実行されてしまう攻撃です。これによりCookie情報が盗まれたり、フィッシングの被害が発生したりします。特に、掲示板やコメント機能、口コミ、検索ボックスなどのユーザーの入力によって表示内容が動的に変わる部分で被害が発生しやすいです。

IPA(情報処理推進機構)が公表した「2024年第1四半期 脆弱性対策情報データベースJVN iPediaの登録状況」によると脆弱性の種類別件数は、クロスサイトスクリプティング(XSS)が2,198件、境界外書き込みが891件、SQLインジェクションが876件、クロスサイトリクエストフォージェリ(CSRF)が611件、認証の欠如が328件と、XSSが最も多いことがわかります。

クロスサイトスクリプティング(XSS)の流れ

まず、XSS攻撃の大まかな流れを解説します。基本的な攻撃の流れは次の通りです:

  1. 攻撃者がWebサイトの入力フォームやURLパラメータに悪意のあるスクリプトを入力し、送信します
  2. Webサイト側で適切な入力検証やエスケープ処理を行なっていなかった場合、攻撃者が注入したスクリプトがそのままWebサイトに注入されます
  3. 他のユーザーがそのWebページを閲覧したり、悪意のあるリンクをクリックしたりするとブラウザ上でプログラムが実行されます
  4. ユーザーのCookie情報が攻撃者に送信されたり、フィッシングやマルウェアの被害が発生します

クロスサイトスクリプティング(XSS)の例

大まかなXSS攻撃の流れを把握できたところで、具体的にどのようにXSS攻撃が行われるのか例を見てみましょう。ここでは、Googleが提供している「XSS Game」というXSS攻撃を体験できるWebサイトを例として使用しています(XSS Gameについては、この記事の最後に詳しく言及しています)。まずは以下の動画をご覧ください:

この例では、最初に検索ボックスに文字列Hello Worldと入力しています。その後Try againボタンをクリックして検索画面に戻り、今度はHTML(HyperText Markup Language)のh1タグをつけて同じ文字列Hello Worldを入力して送信しています。

この例で注目すべき点は、全く同じ文字列Hello Worldを入力しているにも関わらず、HTMLのh1タグを付けた場合と付けなかった場合とで検索結果ページの表示が変わっているところです。

ただのHello Worldという文字列を検索した場合の検索結果ページは、通常の文字と同じ小ささでHello Worldと表示されているのに対し、h1タグをつけて入力したHello Worldの検索結果ページでは、中央に大きくHello Worldと表示されています。これは、見出しを表すh1タグをただの文字列としてではなく、HTMLとしてWebサイトが処理してしまっていることを表します。

本来は、検索ボックスに入力された値を検証し、必要であればエスケープ処理を行なった上で、どのような入力値でもただの文字列として扱うようにWebサイトを実装する必要があります。しかし、この動画の例ではそのような適切な処理が行われていないためh1タグがついているHello WorldをHTMLのプログラムとして扱ってしまっています。

このようなXSSに対する脆弱性があるWebサイトにJavaScriptで書かれたスクリプトが入力されるとどうなるでしょうか。その例をご覧ください:

ここで、上の動画の例で入力されているJavaScriptがどのような意味を持つプログラムなのかを簡単に解説します。

<script>alert("Test")</script>

最初の<script>は、ブラウザに対してここからJavaScriptのコードが始まることを示しています。次のalert("Test")は、ブラウザ上にTestというメッセージを表示するポップアップウィンドウ(アラートボックスともいう)を作成するための記述です。そして最後の</script>は、JavaScriptのコードがここで終了することを示しています。

本来であれば、万一、JavaScriptのようなスクリプトが検索ボックスに入力されたとしても、プログラムコードとしてではなく単なる文字列として扱わなければならないところ、XSS攻撃に対する防御策が実装されていないWebサイトでは、攻撃者からのスクリプトを受け付けてしまいます。ここで取り上げた2つの例はとても単純なものでしたが、実際のXSS攻撃においては他のユーザーのCookie情報を盗むような高度で危険なスクリプトが用いられます。

クロスサイトスクリプティング(XSS)の被害事例

クロスサイトスクリプティング(XSS)は古くから存在している脆弱性ですが、依然として多くのWebサイトで見られます。ここでは最新の被害事例をいくつか紹介します。

このように多くのユーザーがいるWebサービスでもXSS攻撃の被害を受けていることがわかります。このような被害事例は、Webサービスのセキュリティの重要性を再確認させるものであり、脆弱性に対する対策が不可欠であることを示しています。ユーザーの安全を守るために、継続的なセキュリティ対策が求められます。

クロスサイトスクリプティング(XSS)とクロスサイトリクエストフォージェリ(CSRF)の違い

名称が似ていることで混同されがちなクロスサイトスクリプティング(XSS)とクロスサイトリクエストフォージェリ(CSRF)について、ここで取り上げたいと思います。どちらもWebアプリケーションに対する攻撃手法ですが、それぞれ仕組みが異なります。まず、大まかなXSSとCSRFの違いについて以下の表にまとめます:

特徴XSSCSRF
攻撃対象ユーザーのブラウザサーバーとユーザー間のセッション
攻撃手法悪意のあるスクリプトの注入ユーザーを介した不正なリクエストの送信
目的ユーザー情報の盗難、操作の乗っ取りなどユーザーに意図しない操作を行わせるなど
必要な条件Webサイトのスクリプト処理の不備ログインしているユーザーのセッション

XSSは、これまで解説してきた通り、攻撃者が悪意のあるスクリプトをWebサイトに注入し、他のユーザーのブラウザ上で不正なプログラムが実行される攻撃です。この攻撃によりユーザーのCookie情報を盗まれたり、そのユーザーになりすまされて不正な操作が行われたりする被害が発生します。

一方CSRFは、攻撃者が他のユーザーのログイン(認証)しているセッションを悪用し、ユーザーの意図しない操作(例えば、アカウント情報の変更、銀行口座への不正送金など)のリクエストを勝手にサーバーに送信する攻撃です。このように、XSSとCSRFは仕組みの異なる攻撃手法ですが、どちらもWebアプリケーションに重大な被害を与える可能性があります。

クロスサイトスクリプティング(XSS)対策

XSS攻撃を防ぐためには、基本的な対策をしっかりと講じることが重要です。

あらゆるWebアプリケーションで必須のXSS対策(2つ)

  1. HTTPレスポンスに文字エンコーディングを明示する
    • HTTPレスポンスヘッダーに文字エンコーディングを指定する
    • ブラウザが正しくテキストを解釈できるようにし、エンコードされた文字がそのまま実行されることを防ぐ
  2. 特殊文字のエスケープ処理
    • HTMLの要素に対してhtmlspecialchars関数を使用し、特殊文字をエスケープする
    • HTMLの属性値に対しても同様にhtmlspecialchars関数で特殊文字をエスケープしてから属性値をダブルクォーテーションで囲む

可能な限り行いたいXSS対策(5つ)

  1. ブラウザにX-XSS-Protectionを設定する
    • ブラウザにXSSフィルタを有効にするよう指示する設定で、既知のXSS攻撃を防ぐことができる
    • HTTPレスポンスヘッダにX-XSS-Protection: 1; mode=blockのように設定する
  2. バリデーションを実装する(入力値検証)
    • ユーザーからの入力を検証する機能を実装する
    • 許可された値のみを入力として受け付けるように制限することで万一悪意のあるスクリプトが注入されてもXSS攻撃の発生を防ぐ
  3. CookieにHttpOnly属性を付与する
    • CookieにHttpOnly属性を設定することで、JavaScriptからはCookie情報にアクセスできないようにする
    • この属性を付与することでCookie情報の盗難を防ぐことができる
  4. コンテンツセキュリティポリシー(CSP)の設定
    • CSPを設定することで、信頼できるソースからのスクリプトのみを実行させるようにする
    • 外部からの悪意のあるスクリプトの実行を防ぐことができる
  5. TRACEメソッドを無効化する
    • Webサーバー設定でTRACEメソッドを無効にする
    • nginxではデフォルトで無効になっているが、他のサーバーでも確認が必要

これらの対策をできるだけ複数講じることで、XSS攻撃のリスクを低減できます。Webアプリケーションのセキュリティを向上させるために、ぜひ実践してください。

PHPにおけるXSS対策例

上記の対策をどのように実践すればよいか、ここではPHPを用いる場合の具体例を紹介します。

出力データのエスケープ例:

データベースから取得したデータをエスケープ処理してから表示するようにします。以下のプログラム例ではhtmlspecialchars関数を使ってHTMLの特殊文字をエスケープし、ブラウザ上でスクリプトが実行されるのを防ぐことができます。

<?php
// データベースからのデータ取得
$data = "<script>alert('XSS攻撃');</script>";

// htmlspecialchars()を使用してエスケープ処理
echo htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
?>

JavaScriptのエスケープ例:

ユーザーの入力値をJavaScript内で使用する場合のエスケープ処理の例です。addslashes関数を使用して、JavaScriptの文字列内で使用するためにエスケープ処理を行っています。

<?php
$user_input = $_POST['user_input'];
$safe_input = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
?>

<script>
    var userInput = "<?php echo addslashes($safe_input); ?>";
    console.log(userInput);
</script>

URLパラメータのエスケープ例:

URLパラメータにユーザーの入力値を含める場合もエスケープが必要です。rawurlencode関数を使用して、URL内に含めるユーザーの入力値をエスケープし、URLパラメータの不正な操作を防ぎます。

<?php
// ユーザーの入力値を取得
$user_input = $_GET['user_input'];

// rawurlencode()を使用してエスケープ処理
$safe_input = rawurlencode($user_input);

// サニタイズされたURLの生成
echo '<a href="example.php?param=' . $safe_input . '">リンク</a>';
?>

入力フォームのエスケープ例:

入力フォームのデフォルト値にユーザーの入力値を使用する場合もエスケープが必要です。フォームに入力された値を安全に表示するためにここでもhtmlspecialchars関数を使用しています。

<?php
$user_input = $_POST['user_input'];
$safe_input = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
?>

<form method="post">
    <input type="text" name="user_input" value="<?php echo $safe_input; ?>">
    <input type="submit" value="送信">
</form>

入力データのサニタイズ(無害化)例:

ユーザーからの入力値をそのまま出力しないようにサニタイズします。ユーザーからの入力データをhtmlspecialchars関数でサニタイズし、安全に表示します。

<?php
// ユーザーの入力値を取得
$user_input = $_POST['user_input'];

// htmlspecialchars()を使用してエスケープ処理
$safe_input = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');

// サニタイズされたデータの出力
echo $safe_input;
?>

コンテンツセキュリティポリシー(CSP)の導入例:

CSPを設定し、外部からのスクリプトの実行を制限します。以下はヘッダーにCSPを追加する例です。

<?php
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';");
?>

HTTPOnly属性の設定例:

HTTPOnly属性を設定することでJavaScriptからはCookie情報にアクセスできないようにし、XSS攻撃によるCookie情報の盗難を防ぎます。

<?php
setcookie("session", "value", [
    'httponly' => true,
    'secure' => true,
    'samesite' => 'Strict',
]);
?>

ここではPHPにおけるXSS対策として、入力値のエスケープやURLパラメータのサニタイズ、CSPやHTTPOnly属性の設定例を紹介しました。これらの対策例を複数組み合わせることでXSS攻撃のリスクを低減し、安全なWebアプリケーションを提供することができます。

JavaScriptにおける注意点

特に、JavaScriptを使用したWebアプリケーションはXSS攻撃のリスクが高くなります。ここでは、JavaScriptにおけるXSS対策の注意点について良い例・悪い例を見ていきます。

動的なHTMLの生成に注意する

次の悪い例では、ユーザーの入力値をエスケープせずそのままHTMLに挿入しています。このようなコードでは、もし攻撃者によって悪意のあるスクリプトが注入されてしまった場合、そのまま実行されてしまいますので注意しましょう。

悪い例:

// ユーザーの入力をそのままHTMLに挿入する
document.getElementById('output').innerHTML = userInput;

一方、下記の良い例では、HTMLの特殊文字をエスケープできるtextContentを使用してユーザーの入力値を安全に表示しています。

良い例:

// テキストノードを使用してユーザーの入力をエスケープする
document.getElementById('output').textContent = userInput;

innerHTMLの使用を避ける

innerHTMLを使用するとXSS攻撃のリスクが高まることがわかっているので、可能な限り避けましょう。

悪い例:

// innerHTMLを使用するとXSSのリスクが高まる
element.innerHTML = '<div>' + userInput + '</div>';

ここでもtextContentを使用し、ユーザーの入力をエスケープします。

良い例:

// textContentを使用して安全にテキストを挿入する
element.textContent = userInput;

URLをエスケープする

下記はURLにユーザーの入力値をそのまま挿入する悪い例です。

悪い例:

// ユーザーの入力値をそのままURLに含める
window.location.href = 'https://example.com/?param=' + userInput;

下記はencodeURIComponentを使用してユーザーの入力値をエスケープし、URLを安全に扱う良い例です。

良い例:

// encodeURIComponentを使用してエスケープする
window.location.href = 'https://example.com/?param=' + encodeURIComponent(userInput);

HTML属性値をエスケープする

次は、HTML属性値にユーザーの入力値をそのまま挿入する悪い例を見てみましょう。

悪い例:

// 属性値に直接ユーザーの入力を含める
element.setAttribute('data-user', userInput);

悪い例で用いられているsetAttributeの代わりに、DOMPurifyライブラリを使用してユーザーの入力値をサニタイズする良い例を以下に示します。

良い例:

// DOMPurifyライブラリを使用してユーザーの入力値をサニタイズする
var cleanInput = DOMPurify.sanitize(userInput);
element.setAttribute('data-user', cleanInput);

コンテンツセキュリティポリシー(CSP)を導入する:

HTMLのhead内にCSPを設定する良い例を下記に示します。

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';">

クロスサイトスクリプティング(XSS)のテスト

これまで見てきた通りXSS攻撃は、ページが動的に生成される部分に悪意のあるスクリプトが挿入されて発生します。つまり、Webサービスにおいてコンテンツが動的に生成される部分を重点的にテストし、XSSの脆弱性がないか確認することが大切です。ここでは、XSSをテストする方法について解説します。

XSSのテスト手順

まずは、XSSをテストする大まかな手順を下記に示します:

  1. テスト環境の準備
    • テストを行うための環境を整える
    • ローカル環境やテストサーバーを用意し、Webアプリケーションを実行できる状態にする
  2. テスト対象の特定
    • WebサービスにおいてXSS攻撃が発生しそうな部分を特定する
    • コメント欄、検索ボックス、フォームの入力欄、URLパラメータなど
  3. テストスクリプト(ペイロードともいう)の作成・挿入・送信
    • XSSの脆弱性がないかテストするスクリプトを用意する(alert()print()など)
    • 2. で特定したテスト対象にテストスクリプトを挿入し、送信する
  4. 結果の確認
    • アラートダイアログや印刷画面が表示された場合は、XSSの脆弱性が存在することを意味する
    • 表示されなかった場合でも異なるスクリプトで再度テストを行う

Webサイトにおける入力フォームをテストする例

ここでは簡単な具体例として、一般的なWebサイトにある入力フォームをテストする方法を見ていきます。

テスト手順:

  1. Webサイトの入力フォームを列挙する(例えば、コメント欄や検索ボックス)
  2. 入力フォームに下記のようなテスト用のスクリプトを入力し、送信してみる
  3. アラートボックスが表示されるか確認する

テストスクリプト:

<script>alert('XSSに対して脆弱です');</script>

結果確認:

アラートボックスが表示された場合、その入力フィールドはXSS攻撃に対して脆弱です。アラートボックスが表示されなかった場合でも、さらに詳しいテストが必要となることもあります。

URLパラメータをテストする例

次に、URLパラメータをテストする方法を見ていきます。

テスト手順:

  1. URLパラメータを用いているWebページにアクセスする(例えばexample.com?name=valueなど)
  2. URLパラメータname=valueに下記のようにスクリプトを追加して送信してみる
  3. ページが読み込まれた際にアラートボックスが表示されるか確認する

スクリプト:

example.com?name=<script>alert('XSSに対して脆弱です');</script>

結果確認:

アラートボックスが表示された場合、そのURLパラメータはXSSに対して脆弱です。

ここでは、入力フォームとURLパラメータをテストする2つの例を取り上げました。XSSのテストの基本は、テスト対象に実際にスクリプトを入力してみて、それが実行されるかどうかを確認する地道な作業の積み重ねです。もしXSSの脆弱性が見つかった場合は、適切なエスケープ処理やサニタイズを実装します。

Googleが提供するXSSを体験できるサイト「XSS Game」

Googleが提供する「XSS Game」は、XSS攻撃の仕組みを体験しながら学習できるインタラクティブなWebサイトです。Webアプリケーションのセキュリティを学びたい方にとって非常に有益なリソースです。

XSS Gameの特徴

ここでは、XSS Gameの特徴を簡単に示します:

  • 実践的な学習環境
    • 実際のXSS攻撃を模した課題を通じて、攻撃の仕組みと防御方法を学べるように設計されている
  • 段階的な難易度
    • 複数のレベルで構成されており、徐々に難易度が上がるようになっている
    • 初心者から上級者まで、自分のレベルに応じて挑戦することが可能
  • 即時的なフィードバック
    • 各課題に対して即時にフィードバックが提供されるため、自分の理解度をその場で確認できる
  • ブラウザでの簡単操作
    • ブラウザからWebサイトにアクセスするだけでプレイできる
    • 初期設定が不要で、手軽に学習を始めることができる

XSS Gameの使い方

  1. アクセス
    • XSS GameのWebサイトにアクセスします
  2. レベルの選択
    • 初めての方はLevel 1から段階的に始めるのがおすすめ
    • 各レベルには具体的な課題が設定されており、それをクリアすることで次のレベルに進むことができる
  3. 課題の挑戦
    • 実際に課題に挑戦し、XSS脆弱性を見つける
  4. 学習の進行
    • 課題をクリアしていくことで、XSS攻撃に関する知識が深まる
    • 攻撃に関する知識を得ることで、セキュリティを強化するための防御についても学ぶことができる

このように、Googleの「XSS Game」は楽しく、インタラクティブにXSS攻撃の理解を深めることができる優れた学習ツールです。実際の攻撃シナリオを通じてXSSの仕組みとその対策を実践的に学ぶことができます。ぜひ挑戦してみてください。

XSSチートシート(Cheat Sheet)について

PortSwiggerが提供している「Cross-site scripting (XSS) Cheat Sheet」もXSS攻撃に関する理解を深め、その防御策を学ぶことができる非常に有用なリソースです。セキュリティの専門家やWeb開発者にとって実践的なガイドラインと豊富な情報を提供しています。

XSS Cheat Sheetの特徴

  • XSSに関する詳細な説明
    • XSSについて基本概念から高度な攻撃手法まで詳細に説明している
    • 初心者から上級者まで、XSSに関する知識を体系的に学ぶことができる
  • 多様なペイロード
    • 様々な状況で使用できるXSS攻撃のペイロード(スクリプト)のリストを提供している
    • 一般的な攻撃から特定の条件下での高度な攻撃までが含まれている
  • 防御策のガイドライン
    • XSS攻撃からアプリケーションを守るための具体的な防御策やベストプラクティスが詳しく解説されている
  • 実践的な例
    • 実際のスクリプトの例やシナリオを用いて、どのようにXSS攻撃が実行されるのかを具体的に示している
    • 理論だけではなく、実践的な実装にも役立つ
  • 定期的な更新
    • PortSwiggerは、セキュリティ分野でのリーダー企業である
    • 最新の脆弱性情報や攻撃手法を反映したチートシートを定期的に更新している

XSS Cheat Sheetの活用方法

  1. XSSの基本を学ぶ
    • 初心者はまず、XSSの基本概念と種類について学ぶことができる
    • XSSの仕組みを理解し、どのように防御すべきか把握する
  2. 攻撃手法の理解
    • 様々なペイロードを通じて、実際のXSS攻撃がどのように実行されるのかを学ぶ
    • 攻撃者の視点から脆弱性を発見するスキルを身につけることができる
  3. 防御策の実装
    • 提供されているガイドラインに従い、Webアプリケーションに防御策を実装する
  4. 最新の情報をフォロー
    • 定期的にチートシートを確認し、最新の攻撃手法や防御策を把握する
    • 攻撃手法も、それに対する対策方法も常に進化しているため、最新情報のフォローは不可欠

このように、PortSwiggerの「Cross-site scripting (XSS) Cheat Sheet」は、XSS攻撃に関する包括的な情報を提供している優れたリソースです。XSS攻撃に関する知識を深め、防御策を実装するための実践的なガイドとして、ぜひこのチートシートを活用してください。

まとめ

XSS対策は、Webアプリケーションの安全性を確保するために不可欠です。この記事では、できるだけ多くの具体例を取り上げながら、XSS攻撃について解説しました。今回紹介した対策方法を多層的に実装したり、有効なリソースを活用することで、XSS攻撃の脅威からWebサービスを守りましょう。

いまなら無料脆弱性診断実施中!

テストオウルでは、期間限定で無料の脆弱性診断サービスを提供しています。当社の脆弱性診断サービスは、国際認定資格を保有するセキュリティのプロフェッショナルがお客様のシステムやWebサービスに潜む脆弱性を専門的に診断し、セキュリティ対策を支援いたします。セキュリティは現代のビジネスにとって極めて重要な要素です。情報漏洩や不正アクセスなどのリスクを最小限に抑えるために、ぜひ無料脆弱性診断サービスをご活用ください。詳細やお申し込みに関しては、こちらのフォームよりお気軽にお問い合わせくださいませ。

参考文献

よかったらシェアしてね!
目次