クロスサイトスクリプティングって何だ?

Wikipediaによると

クロスサイトスクリプティング(英: cross site scripting)とは、 ウェブページの部分をユーザからの入力をそのままエコーバック (オウム返し)することによって生成しているアプリケーションの セキュリティ上の不備を利用して、サイト間を横断して悪意のある スクリプトを注入する攻撃のことをいう。また経緯上、 それを許してしまう脆弱性についても、このように呼ばれている。

とのことらしい。 全然わからんかったので、自分でHTMLを書いてみたらようやく理解できた。

超簡単なXSSのサンプル

入力内容をそのままページに表示するプログラムを書いてみる。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
</head>
<body>
  <p></p>
  <h4><a href="http://google.com">Google</a></h4>
  <ul>
    <li>今日はいい天気</li>
  </ul>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <input type="text" name="name" id="inputed_text" value="">
  <input type="button" name="name" id="btnRegist" value="投稿">
  <script type="text/javascript">
    $(function() {
      $('#btnRegist').on('click', function() {
        var inputed_text = $('#inputed_text').val();
        $('ul').append('<li>'+ inputed_text +'</li>');
      });
    });
  </script>
</body>
</html>

f:id:Turing:20160828213528p:plain

投稿ボタンを押すと入力内容がそのままページに表示される。これはサンプルとしてHTMLだけで書いたが、実際には入力内容はサーバーに保存され、このWebサービスを使う全ユーザが同じ内容を共有できるようになっていると仮定する。

この入力欄に下記のような一文を挿れて投稿してみる。

</li>
<script type="text/javascript">
  $('a').attr('href','http://yahoo.co.jp');
</script>
<li>

するとHtmlはこのようになる。

<html lang="ja"><head>
  <meta charset="utf-8">
</head>
<body>
  <p></p>
  <h4><a href="http://yahoo.co.jp">Google</a></h4>
  <ul>
    <li>今日はいい天気</li>
  <li></li> <script type="text/javascript">   $('a').attr('href','http://yahoo.co.jp'); </script> <li></li></ul>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <input type="text" name="name" id="inputed_text" value="">
  <input type="button" name="name" id="btnRegist" value="投稿">
  <script type="text/javascript">
    $(function() {
      $('#btnRegist').on('click', function() {
        var inputed_text = $('#inputed_text').val();
        $('ul').append('<li>'+ inputed_text +'</li>');
      });
    });
  </script>
</body></html>

ul要素(リスト)の中にscriptが埋め込まれ、Googleのリンク先が Yahoo!JAPANに変わっている。

今回のサンプルはリンク先を変えただけだが、input要素のPostの送信先を改ざんしてクレジットカード番号を抜き取るというようなことが行われているらしい。

対策は?

入力内容に含まれる危ない文字(<とか>とか&やら)をエスケープするのが基本的な対策法。

RubyOnRailsはRails2までは、明示的なエスケープ処理を書く必要があったけどRails3からはエスケープがデフォルトになったんだそう。