推奨しないXSS対策と、その理由
概要
本記事ではXSS対策について記載する。
XSSはWebアプリケーションの脆弱性であり、最もメジャーな脆弱性の1つだ。
本脆弱性は、主に入力値がレスポンスに出力される際に「”’<>」等の特殊文字がエスケープされていないことが原因で発生する。被害の例としては、フィッシングサイトにユーザがアクセスしてしまった際に、そこから任意のスクリプトが入力されたリクエストが攻撃対象サイトに送信され、そのサイトで任意のスクリプト(攻撃者のサーバにCookieの値を送信する等)が動作してしまう反射型XSSが有名だ。
詳しくはIPAのサイトを見てほしい。
本記事では推奨されるXSS対策と、推奨しない対策を紹介する。
反射型XSSの例
まず、反射型XSSの最も基本的な例を提示する。
XSSの脆弱性は以下のサイト(例はOWASP BWAの練習サイト)の「View File」ボタンに存在する。本ボタンを押した際のパラメーター「textfile」の値がエスケープされずにレスポンスに出力される。
ここでユーザはメール等からフィッシングサイトにアクセスしてしまい、本サイトのボタンを押してしまったとする。
以下のようなリクエストが攻撃対象サイトに向かって送信される。
攻撃対象サイトに画面遷移し、スクリプトが動作する。
レスポンスを確認すると、入力値がそのままレスポンスに出力されていることがわかる。
本例ではalertという無害なスクリプトが動作しただけだが、スクリプトの内容を変更すれば、本サイトに紐づくユーザのCookieを攻撃者のサーバに送信したり、正しいドメインを表示したまま本サイトの内容を一時的に変更することも可能になる。
推奨される対策(エスケープ処理)
XSS対策として最も推奨されるのは「HTML生成時に、出力するデータを全てエスケープする」である。
これはIPAが推奨している手法でもある(上記のリンク参照)。
本手法の最大の利点は、正しくエスケープすれば確実にXSSが防げる点だ(データが出力される場所によってはエスケープ方法が異なる点には注意する)。
しかし、世の中には何故か異なる対策を実施・推奨している人たちもいる。確かに異なる方法でもXSSは防げるが抜け道が存在する場合、そのサイトは危険になる。
推奨しない対策(入力値の制限)
ユーザの入力値に制限を加える対策は確かに有効だ。
例えば「数字のみ入力を許可し、それ以外の文字列が入ればサーバ側で拒否する」という対策を行えば、XSSが動作する可能性は0だろう。
しかし、本対策には穴が存在する。対策が非常に大変だという点だ。
例えばシステムの規模が非常に小さく、数個のパラメータしか存在しないのならば本対策は簡単だろう。しかし、多くのシステムでは画面は複数存在し、それに伴いパラメータの数は数十から数百になるシステムが多数を占めるはずだ。
そうなると「電話番号を示すパラメータに対する入力値制限」「住所に対する入力値制限」….と、関数の管理がパラメータに比例して増えていくのは想像できる。
エスケープ処理ならば共通した少数の関数で対応できるのに、本対策では大量の関数で対策を行うことになる。これらはシステムの無用な複雑化を招き、バグの元になる(この画面では入力値チェックをしていたのに、この画面では漏れていた…という例は多く見てきた)。
また、入力制限の一種として「scirpt」や「<>」等の文字列をブラックボックス的に禁止するやり方は特に抜け漏れが多いので推奨しない。
これらの対策はエスケープ処理と合わせて実施すれば有効な対策だが、これのみでXSSを防ぐことは難しいと考える。
推奨しない対策(CSRFtoken、Refererチェック)
上記のXSSの例を見た人の中にはCSRFと似ていると感じた人も多いのではないか。確かに反射型XSSとCSRFは非常によく似ている。どちらもフィッシングサイトにユーザを誘導して、リクエストを送信させることで攻撃が成り立つ。
そのためCSRFと同じ対策でXSSが防げるようにも思える。事実、正しくCSRF対策が全画面に適応されていれば、罠サイトから直接リクエストを送信し、任意のスクリプトを実行させるという攻撃は不可能になる。(CSRFtokenはユーザにセッションに対応する値はわからないし、Refererをチェックしていればフィッシングサイトのドメインは拒否されるため)。
しかし、本対策には問題が存在する。
まず、全画面遷移にCSRFtoken、Refererチェックを行うのか?という問題が出てくる。これらの処理を全画面に行えばユーザアビリティはかなり下がる(途中の画面からアクセスできなかったり、戻るボタンが使えなかったり)。
次に格納型XSSには無意味だ。格納型XSSは攻撃者が入力したスクリプトがDBに書き込まれ、ページにアクセスするたびにスクリプトが動作するXSSであり、これはCSRFtoken等では防げない。
また、ユーザにスクリプトを書き込ませるという攻撃手段を取られると防げない。例えばフィッシングサイト内に「100万円が欲しかったら、このサイトにアクセスして、F12を押して、この部分に「<scirpt>~」を入れて…」という命令をユーザに信じさせることができれば、攻撃は可能になる。
「こんなバカな方法に引っかかる人間など存在しない」と考える人が多数だろうが、そういう人は迷惑メールフォルダを見てみよう。「10億円の遺産をあげます」だとか「アイドルと付き合えます」だとか、こういう文章に引っかかる人が存在するから、こういうメールは送信されているのである。そう考えれば、上記の方法に引っかかる人がいない保証はどこにもない(ITに疎い人は特にである)。
このようにCSRF対策をそのままXSSに適応するのは全てのパターンで安全になるわけではない。やはりエスケープ処理とセットで実施するべき対策だと考える。
推奨しない対策(WAF)
WAFはリクエストの内容を調査し、脆弱性を攻撃するパターンの文字列が含まれていれば、リクエストを破棄してくれるファイアウォールの一種だ。
確かにWAFは強固な手段であり多くの攻撃を防御してくれるが、世の中に完璧なWAFやIPSなど存在しない(存在しているのならば、世の中から脆弱性診断という業務はなくなる)。
例えばWAFをすり抜ける攻撃パターンというのは、研究者・攻撃者共に日々開発されているし、それらは公に出回っている。攻撃者が昨日発見した「すり抜けるパターン」に対して、今日WAFが対応するのは難しいと考えられる(それらはWAF販売元の努力にも依存し、ユーザ側からは見えにくい)。
特にXSSはシステムごとに様々な攻撃パターンが考えられ、単純なブラックリスト方式では防御が難しいと考えられる。
やはりWAFも有効な対策ではあるが、エスケープ処理とセットで使うべきだろう。
まとめ
本記事では1つの推奨する対策と、3つの推奨しない対策について記載した。
何故、IPAがエスケープ処理を最も推奨しているか考えよう。それが最も効率的にXSSを防御できるからだ。
確かにXSSの防ぎ方は直感的には多数あるが、それらの多くには抜け道が存在する。「この方法で、この脆弱性を防げるか?」という疑問は、専門家でも即答できないものだ。そのため、開発者が直感で思いついた対策ではなく、専門的な機関が推奨する対策を愚直に実施することを強くお勧めする。