メールアドレスの「ルール」に関する話題が盛り上がっていますね。
これらのエントリに異論があるわけでありません。メールアドレスに関するルールというとRFC5322などがあるものの、現実の運用では簡易的な仕様を用いている場合が大半である…という事情は、私も以前ブログに書きました。、
本稿では、「空前のメールアドレスのルールブーム(?)」に便乗する形で、RFC5322に準拠したメールアドレスで、XSSやSQLインジェクションの攻撃ができることを紹介します。と言っても、SQLインジェクションについては、過去に書きましたので、本稿では、RFC5322バリッドなメールアドレスでSQLインジェクションとXSSの両方ができるメールアドレスを紹介します。
まず、攻撃対象として、以下のログインスクリプトを用います。メールアドレスはfilter_varを用いてメールアドレスとしての妥当性を確認し、パスワードは英数字のみであることをctype_alnumを用いて確認しています。
次に、ログイン失敗の場合です。
これに対する攻撃メールアドレスですが、XSS攻撃に必要な記号文字 < や > はダブルクォートで囲まないとメールアドレスのローカルパート(@の左側)では使えないため、ダブルクォートで囲ったメールアドレスにします。以下にそのような例を示します。
このメールアドレスを先のログインスクリプトに指定すると、以下の画面になります。
ちゃんと(?)XSSが発動していますね。OKボタンをクリックすると続いて下記の画面になります。
SQLインジェクション攻撃により、IDが存在しないのにログインに成功しています。
なお、このメールアドレスはRFC準拠なので、ThunderbirdとGmailでは、このメールアドレス(ドメイン名は変えました)に送信可能であることを確認しています。Becky!での送信は括弧のせいでエラーになるようです。
ということで、RFC5322バリッドで、SQLインジェクションもXSSもできるメールアドレスを示しました。
ただし、このメールアドレスは中々に危険です。その理由については私の過去のエントリを御覧ください。このため、この種のメールアドレスを公開Webサイト等で試すことは避けてくださいますようにお願い致します。
*1 phpallで確認したところ、PHP5.3.2までは空白入りのメールアドレスがValidと判定されていましたが、PHP5.3.3以降ではエラーになるようです。
これらのエントリに異論があるわけでありません。メールアドレスに関するルールというとRFC5322などがあるものの、現実の運用では簡易的な仕様を用いている場合が大半である…という事情は、私も以前ブログに書きました。、
本稿では、「空前のメールアドレスのルールブーム(?)」に便乗する形で、RFC5322に準拠したメールアドレスで、XSSやSQLインジェクションの攻撃ができることを紹介します。と言っても、SQLインジェクションについては、過去に書きましたので、本稿では、RFC5322バリッドなメールアドレスでSQLインジェクションとXSSの両方ができるメールアドレスを紹介します。
まず、攻撃対象として、以下のログインスクリプトを用います。メールアドレスはfilter_varを用いてメールアドレスとしての妥当性を確認し、パスワードは英数字のみであることをctype_alnumを用いて確認しています。
実行例を示します。まずは、ログイン成功の場合です。最下行にログインユーザ名が表示されますが、ここにXSS脆弱性があります。<?php
define('USERNAME', 'xxxxx');
define('PASSWORD', 'xxxxx');
$err = $id = $pwd = '';
// ユーザID(メールアドレス)のバリデーション
if (isset($_GET['id']) && filter_var($_GET['id'], FILTER_VALIDATE_EMAIL)) {
$id = $_GET['id']; // ユーザID
} else {
$err .= 'ユーザIDはメールアドレスを指定してください<br>';
}
// パスワード(英数字)のバリデーション
if (isset($_GET['pwd']) && ctype_alnum($_GET['pwd'])) {
$pwd = $_GET['pwd']; // パスワード
} else {
$err .= 'パスワードは英数字を指定してください<br>';
}
if ($err !== '') {
die($err); // バリデーションエラーの場合はエラーメッセージを表示して終了
}
// データベースに接続
$dbh = new PDO('mysql:dbname=test;host=localhost;charset=utf8', USERNAME, PASSWORD);
// SQLの組み立て
$sql = "SELECT * FROM users WHERE id ='$id' AND pwd = '$pwd'";
$stmt = $dbh->query($sql); // クエリー実行
?><html>
<body><?php
echo 'sql= ' . htmlspecialchars($sql, ENT_NOQUOTES, 'UTF-8') . '<br>';
if ($stmt->rowCount() > 0) { // SELECTした行が存在する場合ログイン成功
echo "ログイン成功です(id:$id)";
} else {
echo 'ログイン失敗です';
}
$dbh = 0;
?></body>
</html>
次に、ログイン失敗の場合です。
これに対する攻撃メールアドレスですが、XSS攻撃に必要な記号文字 < や > はダブルクォートで囲まないとメールアドレスのローカルパート(@の左側)では使えないため、ダブルクォートで囲ったメールアドレスにします。以下にそのような例を示します。
ここで、/**/は空のコメントですが、filter_varによるメールアドレスチェックでは(quoted-stringでも)空白がエラーになった(*1)ので、空白の代わりに使用しています。"><script>alert('or/**/1=1#')</script>"@example.jp
このメールアドレスを先のログインスクリプトに指定すると、以下の画面になります。
ちゃんと(?)XSSが発動していますね。OKボタンをクリックすると続いて下記の画面になります。
SQLインジェクション攻撃により、IDが存在しないのにログインに成功しています。
なお、このメールアドレスはRFC準拠なので、ThunderbirdとGmailでは、このメールアドレス(ドメイン名は変えました)に送信可能であることを確認しています。Becky!での送信は括弧のせいでエラーになるようです。
ということで、RFC5322バリッドで、SQLインジェクションもXSSもできるメールアドレスを示しました。
ただし、このメールアドレスは中々に危険です。その理由については私の過去のエントリを御覧ください。このため、この種のメールアドレスを公開Webサイト等で試すことは避けてくださいますようにお願い致します。
*1 phpallで確認したところ、PHP5.3.2までは空白入りのメールアドレスがValidと判定されていましたが、PHP5.3.3以降ではエラーになるようです。