ユーザ入力など内容が不定なものがそのままHTMLに出力されると,クロスサイトスクリプティング(cross-site scripting,XSS)という脆弱性が起こり得ます。
例えば,簡単なフォーム を改悪した簡単なフォーム(悪い見本) では,入力チェックがしてないので,ページの内容を大幅に書き足すことができてしまいます。例えば次のリンクを踏んでみてください:
さらにJavaScriptと併用するなどして,クッキーなどの情報を盗むことができます。
クロスサイトスクリプティングを防ぐには,HTMLへの出力の直前に htmlspecialchars()
という関数を使って < > & "
をそれぞれ < > & "
に置き換えます。
さらに,htmlspecialchars($string, ENT_COMPAT, 'UTF-8')
のように第3引数に文字コードを与えると,不正な文字コードの文字列を削除します。PHP 5.4,PHP 5.5では第3引数のデフォルト値は 'UTF-8'
,PHP 5.6以降では default_charset
の値になりますので,特に指定する必要はなくなります。詳しくはPHPのマニュアルの htmlspecialchars
の項を見てください。
さきほどの簡単なフォーム(悪い見本)に
htmlspecialchars($string, ENT_COMPAT, 'UTF-8')
を入れた簡単なフォーム(GET版)なら,不正なコードの挿入は防げます。でも,別ページから書き込みができることを利用して,なりすまし投稿が簡単にできます。次のリンクを踏んでください:
<a href="form-get.php?onamae=hogehoge">クリックしてね!</a>
書き込んだ覚えがないのに「hogehoge」という名前が投稿されていることがわかります。
GETでなくPOSTなら安全でしょうか?
クリックしてね!
POSTでも同じことができますね(仕組みが知りたければソースを見てください)。
こういった手法をCSRF(cross-site request forgery)といいます。横浜市のサイトに殺人予告を投稿した罪で逮捕された人が,CSRFのリンクを踏んだ無関係な人だったという事件がありました。
CSRF対策にはいくつかの方法があります。上のクリックしてね!というリンクをたどったページの一番下に一つのヒントが書かれているかもしれません。
データベースに問合せを行う際に,ユーザ入力を工夫して不正なSQL文を与え,データを不正に取得したり書き換えたりすることを,SQLインジェクションといいます。
SQLインジェクション対策にはいろいろな方法がありますが,ここではPHPの「PDO」という仕組みを使う場合について,プリペアドステートメントという方法を説明しています。実例についてはPHPのマニュアルのプリペアドステートメントの項を見てください。次は簡単な例です:
$db = new PDO(...); $st = $db->prepare('select * from hoge where user=? and pass=?'); $st->execute(array($user, $pass)); $a = $st->fetchAll();
入力をよくチェックすることも対策になります。例えば $x
が数値であることがわかっていれば,settype($x, "int");
や settype($x, "float");
のようにして型を強制的に整数や浮動小数点数に変換することができます。C言語と同様のキャスト
$x = (int) $x;
や $x = (float) $x;
も使えます。
Last modified: