【セキュリティ最前線】
セキュリティホールをついて遊ぶ
第2回:PHPのSQLインジェクションを実体験
著者:大垣 靖男
公開日:2008/1/18(金)
何故不正なSQL文が実行されたのか?
Webブラウザに表示されたSQLクエリには「・」という、おかしな文字が表示されている(リスト7)。この文字は実際には「0x95,0x27」の2バイトのデータであり、文字化けが発生したことが原因で、このように表示されている。
実は「0x95」はShift SJIS文字エンコーディングのマルチバイト文字のはじまりバイトの1つであり、本来はそれに続く「0x27」で最初のLIKE条件の文字列が終了するはずが、「0x95,0x27」で1つのマルチバイト文字として取り扱われたため、2つ目のLIKE句条件で不正なSQL文の挿入を許してしまったのである。
つまり上記のクエリは実際にはリスト8のように、3つのSQL文として実行されていたことになる。
対策済みのPostgreSQLで実行した場合
PHPスクリプトは変更せず、データベースサーバを最新版のPostgreSQL 8.2.6にして同じテストを行うと、リスト9のエラーメッセージが表示される。
さらに「http://localhost/sql.php?q1=%95&q2=;DROP%20TABLE%20table2;--」のクエリ文字列の中で「%95」を「'」に変更し、「http://localhost/sql.php?q1='&q2=;DROP%20TABLE%20table2;--」という状態で実行すると、別のエラーが表示される(リスト10)。
このようにPostgreSQLは不正なマルチバイト文字エンコーディングを正しく検出し、SQLインジェクションを防止してくれる。
リスト7:SQLクエリの実行結果(再掲)
SELECT * FROM table1 WHERE field1 LIKE '・ or field2 LIKE ';DROP TABLE table2;--';
リスト8:SQLクエリの実行内容
SELECT * FROM table1 WHERE field1 LIKE '・ or field2 LIKE ';
DROP TABLE table2;
リスト9:PostgreSQL 8.2.6でのエラーメッセージ
Warning: pg_query() [function.pg-query]: Query failed: ERROR: invalid byte value for encoding "SQL_ASCII": 0x95 in /home/yohgaki/public_html/sql.php on line 20
SELECT * FROM table1 WHERE field1 LIKE '・ or field2 LIKE ';DROP TABLE table2;--';
リスト10:「%95」を「'」に変更した際のエラー表示
Warning: pg_query() [function.pg-query]: Query failed: ERROR: unsafe use of \' in a string literal
LINE 1: SELECT * FROM table1 WHERE field1 LIKE '\'' or field2 LIKE '...
^
HINT: Use '' to write quotes in strings. \' is insecure in client-only encodings. in /home/yohgaki/public_html/sql.php on line 20
文字エンコーディングベースのSQLインジェクション
この実験では不正なShift JISマルチバイト文字となるデータを生成してSQLインジェクションを実行した。
この方法以外にも「正しい」マルチバイト文字を利用する方法がある。例えば、Shift JISの「表」は「0x95,0x5c」の2バイトで表現される。「0x5c」はASCII文字の「\」のため、文字エンコーディングを考慮しないaddslashes関数でエスケープすると、本来はマルチバイト文字1文字である「表」の後半に余計な「\」を追加してしまう。
この結果として、クオートで囲まれたSQLクエリパラメータは「'+0x95+0x5c+0x5c' ('表\')」といった文字列となる。この文字列はShift JISとして正しいために、サーバ側ではユーザが意図したクエリなのか、SQLインジェクション攻撃の可能性がある不正なデータなのかを判別できない。
文字エンコーディングを利用したSQLインジェクションは、データベースの仕様や設定、PHPスクリプトなどの条件が整わないと実行できないタイプの攻撃だ。しかし、外部から脆弱性が存在しないか確認することは難しくない。このため、通常のSQLインジェクション対策と同様に注意が必要といえる。 次のページ