コネクト株式会社 技術情報コンテンツ | ||
はじめにSantyワーム*1のターゲットとされてしまったphpBB。 ここでは、Santyワームを例にして、Webアプリケーションの脆弱性*2について考えたいと思う。 脆弱性とは?脆弱性は、どんな言語で開発されたWebアプリケーションであっても発生する可能性がある。 PHPのようなスクリプト言語であろうが、コンパイルによって出力された中間コードを用いるJavaのような言語であろうが、可能性は全く変わらない。 脆弱性が言語に依存しないとすれば、どうして脆弱性が生まれるのだろうか。 動作環境の脆弱性まず最初に思い浮かぶのは、動作環境に依存した脆弱性だろう。 PHPに限らず、アプリケーションに脆弱性が発見された場合、ほぼ数日のうちに脆弱性を改善したバージョンが公開されている*3。 もし、レンタルサーバ上でサービスを運用を行っている場合、契約者はPHPなどのアプリケーションを更新する権限を持っていないため、脆弱性に対する処置は管理会社に一任される事となる。 脆弱性の対応がなされない場合、メールなどで管理会社に問い合わせてみると良いかも知れない。 Webアプリケーション側の脆弱性実行環境の脆弱性ばかりがクローズアップされがちだが、Webアプリケーション自体に脆弱性が存在する事も珍しくない。 代表的な例が、[[クロスサイトスクリプティング>セキュリティ指針/クロスサイトスクリプティング]]や[[SQLインジェクション>セキュリティ指針/SQLインジェクション]]である。 これらの脆弱性は、一定のルールに従ったコーディングを行うだけで回避する事が可能である。 裏を返せば、脆弱性に関する対策を施さない若しくは脆弱性について全くの無知であった場合、Webアプリケーションの安全性は全く保障されない事になる。 phpBBがSantyワームに狙われた理由は、phpBBに存在していた脆弱性を悪用する為である。 なぜ脆弱性が生まれるのかPHPから話題はずれてしまうが、“バッファ・オーバーフロー”というキーワードを1度は耳にした事があるだろう。 脆弱性とは、「アプリケーション設計者が想定していない情報を受け取ったときの対処が甘かった事によって生じる“人災”である」と言っても過言ではないだろう。 第2のSantyワームに狙われないためにSantyワームが狙ったのは、phpBBという普及率の高いWebアプリケーションであった。 では、どのような事に気を付けなければならないのか、具体例を挙げて解説しよう。 想定外の値は受け付けないphpBBの脆弱性で狙われたのは、スクリプトを読み込むinclude(require)文の使い方であった。 クエリストリングのactで要求されたベース名に拡張子".php"を加えたスクリプトを読み込む場合、次のようなスクリプトを記述する人も少なくないだろう。 $path = $_REQUEST['act'] . 'php' include($path); このスクリプトは、非常に危険である。 actの値のバリエーションが決まっているのであれば、整合性を確認すべきである。 $valid_arr = array('list', 'edit', 'delete', 'commit'); $act = $_REQUEST['act']; if (!in_array($act, $valid_arr)) { exit('bad act.'); } include($act . '.php'); 上記のスクリプトであれば、actは、list, edit, delete, commit だけが許可され、正しくない場合はexitをする。 このように、アプリケーション設計者が意図している値だけを受け付けるようにすべきである。 クエリストリングの精査は必ず行うありがちな脆弱性として、クエリストリングの精査の甘さが考えられる。 次のスクリプトは、クエリストリングの精査が不十分である。 $num = $_REQUEST['num']; if ($num > 0 && $num < 10) { $sql = "DELETE FROM foo WHERE id=$num"; } このスクリプトに対して、num=1%20OR%201というクエリストリングを要求してみるといい。
fooテーブルにある全ての行が削除されてしまうであろう。 この問題を解決するには、次のような処理を行うべきである。 $num = (int)$_REQUEST['num']; if ($num > 0 && $num < 10) { $sql = "DELETE FROM foo WHERE id=$num"; } このスクリプトでは、変数$numに代入した際に、既に整数型にキャストされるので、前述のような要求があった場合でも、不正な値をSQL文に埋め込まれる心配は無い。 $num = $_REQUEST['num']; if (ctype_digit($num) && $num > 0 && $num < 10) { $sql = "DELETE FROM foo WHERE id=$num"; } else { exit('bad request'); } 最後に今回取り上げた情報だけでは、セキュアなWebアプリケーションを作るのに十分とは言えない。 |