
			【セキュリティ最前線】
セキュリティホールをついて遊ぶ
			第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インジェクション対策と同様に注意が必要といえる。 
 次のページ