SQLインジェクションSQLインジェクションは、 攻撃者が動的なSQLクエリを組み立てる責任があるアプリケーションコードの欠陥を突く手法です。 攻撃者は、アプリケーションの権限が必要な部分にアクセスでき、 データベースからすべての情報を引き出し、既存のデータを改ざんしたり、 危険なシステムレベルのコマンドをデータベースのホスト上で実行できてしまいます。 こうした脆弱性は、開発者が任意の入力をSQL文に結合したり、挿入したりすることで発生します。
例1 表示するデータを分割し ... そしてスーパーユーザーを作成します。(PostgreSQLの例) 以下の例では、ユーザーからの入力が直接SQLクエリに挿入されているため、 攻撃者がデータベースの superuser アカウントを取得できてしまいます。
0; insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) select 'crack', usesysid, 't','t','crack' from pg_shadow where usename='postgres'; -- 0; が正しいオフセットを
指していると同時に、クエリをそこで終端させていることに気をつけてください。
パスワードを取得する恐るべき手段に、サイトの検索結果のページを欺く
というものがあります。攻撃者が必要な作業は、投稿された変数
の中でSQL命令で使用される際に正しく扱われていないものがあるかどう
かを確かめることだけです。これらのフィルタは、通常、
例2 記事...そして(全てのデータベースサーバーの)いくつかのパスワード のリストを表示する
SELECT 文と組み合わせることができます。
' union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable; --
例3 パスワードのリセットから ... (全てのデータベースサーバーで)より多 くの権限を得るまで
' or uid like'%admin% を
$uid に代入するか、または、より多くの権限を得
るために、単純に$pwd に
hehehe', trusted=100, admin='yes と設定すると、
このクエリは以下のように改謬されてしまいます。
攻撃者がデータベースの構造に関して最低限の知識を持っていないと攻撃は成功しないのが明らかです。 しかし、その手の情報はたいてい、とても簡単に入手できます。 たとえば、コードの一部がオープンソースソフトウェアの一部のため、 公開されている可能性があります。 こうした情報は、クローズドソースの場合でも漏洩する可能性があります - エンコードされたり、難読化されたり、コンパイルされていてもです。 - さらに、自作のコードであっても、エラーメッセージを表示することで漏れてしまう可能性があるのです。 他の方法としては、ありがちなテーブルやカラムの名前を使うことが挙げられます。 たとえば、'id', 'username', 'password' カラムを持つ 'users' テーブルを使うログインフォームが挙げられます。
例4 データベースホストのオペレーティングシステムを攻撃する (MSSQLサーバー) 恐ろしい例として、 いくつかのデータベースホストで、 オペレーティングシステムレベルのコマンドがアクセスできる方法を示します。
a%' exec master..xp_cmdshell 'net user test testpass /ADD' --
を$prodに投稿した場合、
$query は以下のようになります。
sa で実行され、
MSSQLSERVERサービスが充分な権限で実行されていた場合、攻撃者は
このマシンにアクセスする権限を有することになります。
この画像は » xkcd から提供いただいたものです。 回避策
SQLインジェクションを回避するおすすめの方法は、
すべてのデータをプリペアドステートメント経由でバインドすることです。
パラメータ化されたクエリは、
SQLインジェクションをすべて防ぐのに十分ではありませんが、
SQL文への入力を与える一番簡単かつ安全な方法です。
パラメータのバインドは、データに対してのみ使えます。 SQLクエリの他の動的な部分については、 許される値の既知の値でフィルタしなければいけません。
例5 PDO のプリペアドステートメントを使い、SQLインジェクションを回避する
プリペアドステートメントは PDO や MySQLi、 そして他のデータベースライブラリでも使えます。 SQLインジェクションによる攻撃は、 セキュリティを考慮して書かれていないコードを攻撃する方法です。 特にクライアント側から入力されるあらゆる種類の入力を決して信用しないでください。これは、select ボックス や hidden input フィールド、Cookie の場合も同様です。最初に示した例は、簡単なクエリが破滅をもたらしうることを示しています。 攻撃を防ぐ戦略として、以下に示すいくつかのコーディングプラクティスに従うことが挙げられます:
これらのケースにおいて、スクリプトまたはサポートされている場合はデータベース自体でクエリのログをとることが有益です。 明らかにログは破壊的な行為を防止することはできませんが、 攻撃されたアプリケーションを追跡する際には有効です。ログ自体は有益ではありませんが、含まれている情報は有益です。通常、より詳細なログをとる方が良いでしょう。 |