PHPにおけるSQLインジェクション対策

PHPにおけるSQLインジェクション対策

SQLインジェクションとは?

アプリケーションでSQLを実行する際に、想定していないSQLを挿入(インジェクション)する攻撃
原因はSQL発行時に問題がある場合が多い。

以下のコードはSQLインジェクションができてしまう例

$query = "SELECT * FROM users WHERE username = '{$_POST['username']}' AND password = '$password_hash'"

$_POST[‘username’]に対して’usename –‘と入力すると「–」以降はコメントアウトされ、SQLは以下のコマンドを実行する。

$ SELECT * FROM users WHERE username = username

ユーザー名だけでチェックをパスできてしまう。

対策

SQL発行時に適切な値が入るようエスケープの処理を加える。
この場合は$_POST[‘username’]に対してエスケープしてあげること。
MySQL関数でのエスケープはmysql_real_escape_string()mysqli_real_escape_string()を使用。
PostgreSQLではpg_escape_string()を使用する。
PDOではPDO::quote()メソッドが用意されている。

なお、このようにデータベース毎にエスケープ関数が用意されているが、用意されていないデータベースもある
その場合はエスケープ関数を自作するかプリペアドステートメントを使用する必要がある。

プリペアドステートメント

エスケープをした文字列を連結するよりもプリペアドステートメントを使用する方が望ましい。
プリペアドステートメントとは、直訳すると「用意された宣言」となる。
PDOで使用した例は以下

$dbServer = 'localhost';
$dbUser = 'root';
$dbPass = 'root';
$dbName = 'test';
$option = array(
	PDO::ATTR_PERSISTENT => true,
	PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET 'utf8'",
	PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING
);

$username = "test_user";

try{
    $pdo = new PDO (dsn,user,pass,option);
    $query = 'INSERT INTO users (username) VALUES (:username)';
    $stmt = $pdo->prepare($query);
    $stmt->bindValue(':username',$username);
    $stmt->execute();
} catch(PDOException $e) {
    echo "接続できませんでした";
}

 プリペアドステートメント(プレースホルダ)には2種類あり、データベースエンジン側でバインドの処理を行う静的プレースホルダと、ライブラリ側でバインドの処理を行う動的プレースホルダがある。
ライブラリ側にバグがあった場合のことを想定すると静的プレースホルダの方が安全といえる。
本来、このプリペアドステートメントは静的プレースホルダの処理を示す言葉であるが、動的プレースホルダを含めて呼ばれることがある。
PDOはプリペアドステートに対応していないデータベースに対応するためにプリペアドステートをエミュレートする機能も備わっている。(PDO+MySQL環境はデフォルトでOnになっている)

上記のコードはオプションで文字エンコードを指定しています

PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET 'utf8'"

これは文字エンコーディングの処理が原因でSQLインジェクションが発生することもあるので、接続時の文字エンコーディング指定をしています。
なお、接続で利用するエンコーディングを変更する場合はAPIを利用した関数を使用しなければいけません。

プリペアドステートメントを利用しているから完全に安全になるわけではないです。
エスケープの処理を誤ればSQLインジェクションを発生させる原因にもなります。

まとめ

なんにしてもセキュリティって大切ですね。
自分のWebサービスだからいいやっていってセキュリティ周りをきちんとしていなかったら、もしもの時大変です。
それに結局困るのはユーザーですからね。
Webサービスもユーザーの信頼を得るのって大切だと思うんですよ。
とまぁ今回は自分の苦手なセキュリティのお勉強でした。

僕自身、PHPのデータベース周りには疎かったりします。
更に言えばセッションはとクッキーに関しては苦手です。
今までどれだけ自分がフレームワークの恩恵を受けて来たのか痛感しました。
やっぱり根本的な部分をきちんと勉強しとかないといけないですね。

SNSでシェア

Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0