XSSというのは誰もが耳にしたことがある有名な攻撃手法だと思います。しかし、恥ずかしながらその具体的な手法や対策について私はあまり知りませんでしたので、今回調べてまとめてみました。
概要
XSS(cross site scripting)は、他のWebサイトへ悪意あるスクリプトを埋め込むことによってそのサイトの権限でスクリプトを実行する攻撃です。
通常、クロスオリジンでのデータ取得はSOPによって制限されていますが、同一オリジンからのアクセスに偽装することでその制限を回避できるのです。(実際には偽装とはいえないかもしれません。そのデータは確かに同一オリジンから送信されているのですからブラウザ側ではどうしようもありません)
インジェクションの方法
では、どのようにして他のサイトへスクリプトを埋め込むのでしょうか。
要するに、与えた文字列が相手のサーバーからそのまま帰ってくるようにすればいいわけですから、最も典型的なのはフォームへのインジェクションでしょう。
しかしながら、通常、フォームに自分で攻撃用のスクリプトを入れることなんてありませんから、あまり問題ないように感じられます。しかし、それをGETパラメータなどに含めたらどうでしょうか。検索結果のページなどではしばしばフォームの入力内容をGETパラメータに含めますので、適切なエスケープがされていなければ、そこに悪意のあるスクリプトを埋め込むことも可能です。URL短縮サービスなどを利用すればよりわかりにくくすることが出来るでしょう。
以上の攻撃手法はユーザの入力を反射しているので特に**反射型XSS (Reflected XSS)**とも呼ばれます。
単純なフォームではなく掲示板のような場合はより深刻です。悪意のあるスクリプトが書き込まれれば、永続的にそのサイトに埋め込まれてしまい、訪問者全員に影響が出てしまうからです。(反射型なら悪意のあるURLを踏んだユーザーにしか影響が出ないのに対し、こちらは正規のURLに訪問したユーザーにも影響が出る)
これはStored XSSまたはPersistent XSSと呼ばれます。
何が出来るのか
SOP(同一生成元ポリシー)を無視できるということです。これがどれだけ危険かは明らかです。具体的には、次のようなことができます。
- ページ改ざん(DOMを使えばいいです)
- セッション奪取(Cookieを読めばいいです)
- そのページのデータを取得(XHRを使えばいいです)
一方、フロントエンドのJavaScriptですから、次のようなことはできません。
- クライアントPCに保存されているファイルを盗む
- 全く別のWebサイト(非攻撃対象)のデータを盗む
- クライアントPCを破壊する(ブラクラなどは別として)
対策
最も重要なのはスクリプトに使われるような文字をescape (sanitize) することです。Webの世界におけるエスケープは、「\」ではなく「&」を使って別な文字列に置き換えます。
具体的に、XSSを防ぐためには以下の文字をエスケープするべきです。
「<」「>」「”」「’」「&」
前者2つはタグを阻止するためですね。次の2つは属性値に出力する際の対策です。最後の&は直接XSSには関わってきませんが、置き換えてあげないとユーザの入力した「&」が表示されなくなるので必要です。(C言語などで「\\」を表示するには「\\\\」としなければならないのと同じです)
まとめ
- XSSは標的のサイトの中にスクリプトを埋め込むので、SOPの制限を受けない
- 対策としてはタグに関連する文字のエスケープが有効
- ユーザーからの入力は信頼しないこと