なぜPHPアプリにセキュリティホールが多いのか?
第24回 無くならないSQLインジェクション脆弱性
SQLインジェクション対策については既に解説済みですが,あまりに多くのSQLインジェクション脆弱性が放置されているので,もう一度SQLインジェクションについて解説します。
SQLインジェクション脆弱性が放置されている背景には,危険性や対策があまりよく理解されていないことがあるのではないかと考えられます。SQLインジェクション攻撃はかなり自動化しやすく,データベースの構造をまったく知らずに攻撃するブラインドSQLインジェクションを自動化するツールも簡単に作れます。
SQLインジェクション対策
本連載中では既に解説済み(第5回~6回,第14回~15回)ですが,もう一度おさらいです。
SQLインジェクション対策には次のような注意事項があります。
- 文字エンコーディングの取り扱いを厳格に行う(第19回~22回を参照)
- クエリを生成する場合,パラメータはすべて文字列として扱いエスケープする
- プリペアードクエリを利用し,変数はすべてパラメータとして渡す
- テーブル,フィールド,SQLの語句等をクエリ作成に利用する場合,安全であることを確認する
SQLクエリのパラメータは,数値型であっても文字列と渡しても正しく処理するデータベースシステムがほとんどです。SQLインジェクション脆弱性は文字列型のフィールドではなく,数値型のフィールドに対する処理の脆弱性のほうが頻繁に発見されています。整数型へキャストするなどの方法もありますが,機械的にすべて文字列としてエスケープしてしまったほうが確実です。
プリペアードクエリもSQLインジェクション対策に利用できますが,万能ではありません。すべてのパラメータを文字列としてエスケープまたはプリペアードクエリのパラメータとしてデータベースサーバに渡しても,テーブル名やフィールド名,SQLの予約語などをチェックなしで渡してしまうとSQLインジェクションが可能になります。
例えば,
http://example.com/query.php?q=syz&order=DESC
のような入力で
通常のクエリ実行
$sql = "SELECT * FROM data WHERE type='".pg_escape_string($conn, $_GET['q'])."' ORDER BY ".$_GET['order'];
pg_query($conn, $sql);
や
プリペアードクエリの実行
$sql = 'SELECT * FROM data WHERE type=$1 ORDER BY '.$_GET['order'];
pg_prepare($conn, 'foo', $sql);
pg_execute($conn, 'foo', array($_GET['q']));
としてしまうとSQLインジェクションが可能になります。テーブル名やフィールド名,SQL文の条件となる句を渡す場合,ホワイトリストで確認してからユーザ入力を利用しなければなりません。
入力チェックの例
if (!in_array($_GET['order'], array('DESC','ASC'))) {
trigger_error('Invalid request', E_USER_ERROR);
eixt; // 確実にスクリプトの実行を停止
}
普通このようなバリデーション処理は,リクエストを受け付けた直後の入力バリデーション処理で,ほかの入力パラメータのバリデーションと同時に行います。バリデーション処理では,すべてのパラーメータの文字エンコーディング,利用されている文字,形式,範囲がアプリケーションが受け入れ可能な値であるかチェックします。
SQLインジェクション対策はこれだけです。入力バリデーションを確実に行い,パラメータをすべて文字列としてエスケープするかプリペアードクエリのパラメータにすればSQLインジェクションは行えなくなります。
XPathインジェクション
データベースシステムがXMLサポートを追加したことにより,XPATHインジェクションのリスクも増加しています。基本的にはSQLと同じで,ユーザ入力を検証し正しくエスケープ処理を行えば問題は発生しません。XPathインジェクションについても既に解説済み(第16回~18回)です。XPathインジェクションもブラインドSQLインジェクションと同様に自動化できます。
XPathを利用したクエリはプリペアードクエリをサポートするデータベースシステムであっても,アドホックなクエリを書く場合がほとんどです。十分注意しないとXPathインジェクションが可能になります。
XPath関連する問題として,“FOR XML”をサポートするデータベース(MS SQL Server 2005/2008等)ではSQLインジェクションにより多くのデータを一度に取得できることがありあす。ブラインドSQLインジェクションと同類の手法を利用してデータを取得するツールも存在します。
実際のSQLインジェクション脆弱性
2009年1月にどれくらいのSQLインジェクション脆弱性がmilw0rm.comで公開されたか数えてみました。82のSQLインジェクション脆弱性が報告されています。ほとんどばオープンソース製品の脆弱性ですが,商用製品の脆弱性も報告されています。その2つの典型的なPHPアプリケーションのSQLインジェクション脆弱性報告を紹介します。
- Max.Blog <=1.0.6 SQLインジェクション
- phpCms 1.x ブラインドSQLインジェクション
milw0rm.comでは脆弱性を攻撃する方法が多数公開されています。攻撃にはSQLの知識さえ必要ありません。
Max.Blog SQLインジェクション
http://www.milw0rm.com/exploits/7885 はMax.BlogのSQLインジェクション脆弱性の攻撃方法を紹介したページです。このページには解説と共に一つのURLが貼り付けてあります。
File affected: show_post.php
This bug allows a guest to view username and password (md5) of a registered user with the specified id (usually 1 for the admin)
http://www.site.com/path/show_post.php?id=-1'+UNION+ALL+SELECT+1,concat('username: ', username),concat('password: ', password),4,5,6,7+FROM+users+WHERE+id=1%23
攻撃用のURLを見ると,show_post.phpのidパラメータに整数が入っていると仮定しており,SQLインジェクションが可能であることが分かります。
id=-1'+UNION+ALL+SELECT+1,concat('username: ', username),concat('password: ', password),4,5,6,7+FROM+users+WHERE+id=1%23
投稿したアーティクルIDの後に,UNIONクエリでuserテーブルからid=1のユーザ名とMD5でハッシュ化されたパスワードが盗み出せることが分かります。攻撃者はURLのサイト名とMax.Blogがインストールされたパス名を変更するだけで管理者のユーザ名とパスワードハッシュを盗めます。
なぜPHPアプリにセキュリティホールが多いのか?
-
Webアプリセキュリティ対策入門〜あなたのサイトは大丈夫?
本書は,Webサイトのセキュリティ確保のために必要な基礎知識と,安全なコードを書くために必要な基礎知識を解説しています。Webアプリケーションは比較的簡単に作成で...
-
はじめてのPHP言語プログラミング入門
Webアプリケーション構築ツールとしてPHPを取り上げた書籍は数多くありますが,言語の解説・入門書としての書籍はあまりありません。 本書は,プログラミング言語として...


