- 2009-04-23 木 22:51:22
- PHP
IPA情報処理推進機構さんで提供されてる
ウェブサイトの脆弱性検出ツール iLogScanner が
昨年11月にバージョンアップしてました。
って、気付くの遅いですね。
気にしてたつもりでしたがアナウンスを見逃してたようです。
個人サイトだと、第三者から客観的に
サイト内を見てもらう機会ってそうありませんし
アプリケーションの現状での脆弱性を確かめられるので
まだの方は使ってみてください。
さて、PHPの基礎体力のココ2日分のアクセスログを
チェックしてみたところこの度はじめて検出されました。
SQLインジェクションが 176件、このうち
攻撃が成功した可能性の高い件数は 0件という結果です。
攻撃とみなされたアクセスは、こんな感じで解析ログに記録されます。
攻撃部分のコード掲載はやめときますが
すべて副問合せを含んだSQLだったので
うちのサーバではまったく機能しない攻撃でした。
とはいえ、持ちあわせの知識で
考えられる限りのこんな対策を施しています。
1.ありえないリクエストをフィルタリング
PHPの基礎体力では、URIに次の値を含むことが無いよう設計していて
リクエストを処理する前にこれらを全てフィルタリングしています。
・制御コード
・ヌルバイト
・演算子やカッコなどの記号
・スペース
・http://
・相対パス
URLエンコードされた(またはされてない)これらの文字が
$_SERVER[‘REQUEST_URI’] に含まれていれば
その時点で、レスポンス 404 Not Found で本文無しを返し
強制終了するようにしています。
多くのプログラミング言語で用いられる
'
シングルクォーテーションや ;
セミコロン、()
カッコなどが
これにひっかかるので大抵はハネてしまいます。
2.リクエストパラメータの変換
上記フィルタに加え、リクエスト毎にも対策しています。
PHPの基礎体力で $_GET や $_POST を使ってるのは
掲示板だけなので、この中で次のような対策を盛り込んでます。
パラメータ view はスレッドの表示方法を選択する値です。
'/php/bbs/thread/4264?view=flat'
今のところ view に指定できる値は ‘flat’ 以外にありません。
‘flat’ か、何も指定が無いかのどちらかです。
そこで文字列を受け取ってはいますが
実際は理論値に直した上で処理してるので
SQLインジェクションとは無縁です。
$view = (!isset($_GET['view']) || 'flat' !== $_GET['view']) ? false: true;
スレッドの一覧表示では
ページの開始位置を決めるパラメータ ‘s’ を使ってます。
'/php/bbs/thread?s=20'
この値は 0以上の整数値、または何も無ししかありませんので
Integer型にキャストしたうえでバリデーションしています。
これが文字列であっても型キャストにより 1 と評価されるので
これまたSQLインジェクションを無効に出来ます。
$s = (isset($_GET['s']) ? (int)$_GET['s']: 0;
$_POSTについても、あらかじめ想定内の
値に変換したうえでバリデーション処理を行っています。
ひと手間増えますが、ユーザから送られてきた値を安心して扱うには
このようなフィルタリングと値の変換、バリデーションは欠かせません。
やられてしまったと悔やむより、やってて良かったでいきましょう。
– – –
それから、サンプルコードの冒頭でよく見かける
スーパーグローバル変数によるローカル変数の初期化。
このままではコードが少し読みやすくなるだけで
他に何の役割もしていません。
$view = $_GET['view'];
私もよくやりますが、
サンプルコードでは要点やロジックがぶれないよう
先のような変換処理やバリデーションを省略して書くことが多々あります。
公にさらされるウェブアプリケーションでは必須処理なので
書いてなくても書いてあるつもりで読みとってください。