Create a gist now

Instantly share code, notes, and snippets.

@tokuhirom /sqli.md
Last active Dec 31, 2015

What would you like to do?

SQLインジェクション対策について

教育的な観点ではなく実務的な観点から、僕の考えをまとめてみる。UTF-8 を利用し、SET NAMES を利用していなくて mysql で、クライアントプリペアドステートメントなケースを想定している。

SQL インジェクションとは

$foo=$_POST[‘id’];
query(“SELECT * FROM foo WHERE id=$foo”);

のように外部からの文字列をそのまま使用してクエリを組みたてたときに、意図せぬ SQL を発行されてしまう脆弱性のことである。

SQL インジェクションの正解

すべてのパラメータを正しくエスケープするか、プレースホルダを使う。

対策

プレースホルダを使う

大体のDBドライバーライブラリにはプレイスホルダーを利用する機能が存在している。

$sth = prepare(“SELECT * FROM foo WHERE id=?”);
$sth.execute($_POST[‘id’])

SQL 自体はリテラルで記述し、その一部後から安全にさしかえられる。

エスケープする

エスケープはたとえば以下のように外部からの入力をエスケープするというものだ。

query(“SELECT * FROM foo WHERE id=” + escape($_POST[‘id’]);

エスケープとプレイスホルダー、どちらを使うか

エスケープしようがバインドしようがどっちでもいい

実際、どっちをつかっても脆弱性は対策されるのでどっちでもいい。エスケープをDBの(クライアント|サーバー)サイドライブラリで行うか、アプリケーションでやるかの差にすぎない。

でもやっぱりプレイスホルダーを中心に

だがしかし、プレイスホルダーが利用可能な場面ではプレイスホルダーを利用する方がよい。

その利点は、コードを見たときに、安全に記述されていることがアキラカであるという点だ。コードレビューの際には、この方式でかかれていない部分のみをチェックすればよくなるので、チェックが簡単になる。記述する人も、「よし、ここは手でくみたてる部分だからしっかり書こう」と身構えるようになるからだ。

動的にSQLをくみたてるときは。。??

サーバーサイドプリペアードステートメントを利用していない場合は以下のようにしてしまえばいい。

$sth = prepare(
	‘SELECT * FROM foo WHERE id IN (‘
		join(‘,’, (‘?’)x@n)
	‘)'
);
$sth.execute(@n);

でもときどきはエスケープも

たとえば phpmyadmin 等をつくったりする場合や USE hogehoge 文をくみたてたりする場合にはプレイスホルダーは使えないので、エスケープする必要がある。そんな時はエスケープするしかない。

公式のエスケープ関数を利用しよう。

だいたいの場合、SQL ライブラリがエスケープ関数を提供してくれているので、それを利用すればよい。

存在しない場合は自前で作らざるを得ないが、ちゃんとしたエスケープ関数を作るのはむずかしい!!! そういう場合は開発元に電話をして作ってくれるようにお願いしてみよう!

まとめ

できるだけプレイスホルダーを使い、プレイスホルダーを使えないところでは公式のエスケープ関数を使おう。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment