なぜPHPアプリにセキュリティホールが多いのか?

第24回 無くならないSQLインジェクション脆弱性

この記事を読むのに必要な時間:およそ 9 分

SQLインジェクション対策については既に解説済みですが,あまりに多くのSQLインジェクション脆弱性が放置されているので,もう一度SQLインジェクションについて解説します。

SQLインジェクション脆弱性が放置されている背景には,危険性や対策があまりよく理解されていないことがあるのではないかと考えられます。SQLインジェクション攻撃はかなり自動化しやすく,データベースの構造をまったく知らずに攻撃するブラインドSQLインジェクションを自動化するツールも簡単に作れます。

SQLインジェクション対策

本連載中では既に解説済み第5回6回第14回15回ですが,もう一度おさらいです。

SQLインジェクション対策には次のような注意事項があります。

  1. 文字エンコーディングの取り扱いを厳格に行う第19回22回を参照)
  2. クエリを生成する場合,パラメータはすべて文字列として扱いエスケープする
  3. プリペアードクエリを利用し,変数はすべてパラメータとして渡す
  4. テーブル,フィールド,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/7885Max.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がインストールされたパス名を変更するだけで管理者のユーザ名とパスワードハッシュを盗めます。

著者プロフィール

大垣靖男(おおがきやすお)

University of Denver卒。同校にてコンピュータサイエンスとビジネスを学ぶ。株式会社シーエーシーを経て,エレクトロニック・サービス・イニシアチブ有限会社を設立。
オープンソース製品は比較的古くから利用し,Linuxは0.9xのころから利用している。オープンソースシステム開発への参加はエレクトロニック・サービス・イニシアチブ設立後から。PHPプロジェクトでは,PostgreSQLモジュールのメンテナンスを担当している。

URLhttp://blog.ohgaki.net/

著書

コメント

コメントの記入