SQLインジェクションが話題になっている。多分あの話題はデマだとは思うが、それが何なのかの知識はあったほうが良いと思う
SQLインジェクションとは
まず、以下のようなテーブルが存在するとする。
CREATE TABLE `table` (
`id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
`content` VARCHAR(255) NOT NULL
) Engine=InnoDB;
次に、以下のようなコードを考える。
<?php
$conn = new mysqli('localhost', 'username', 'password');
$sql = "SELECT * FROM table WHERE content LIKE '%" . $_GET[
'q'] . "%'";
$res = $conn->query($sql);
// 以下、$resを使って処理を行う
これを使うと何が起きるか説明すると、qパラメータにA%' OR '%' = '
と指定すると、全部の行が取得できてしまうのである。これがSQLインジェクションである。
では、どのような対策をすれば良いのだろうか。以下のようにすれば良い。
<?php
$conn = new mysqli('localhost', 'username', 'password');
$eq = $conn->real_escape_string('%' . preg_replace(
'/([%_#])/', '#\\1', $_GET['q']) . '%');
$sql = "SELECT * FROM table WHERE content LIKE '" .
$eq . "' ESCAPE '#'";
$res = $conn->query($sql);
// 以下、$resを使って処理を行う
やっているエスケープ処理は2つ。
- LIKE節のために文字列をエスケープし、%および_に意味を持たせないようにする。その際、 https://www.websec-room.com/2013/12/17/1339 にあるように、ESCAPEを明示的に指定することにより、他のSQLエンジンとの互換性を担保する。
- mysqli::real_escape_stringを呼び出して、SQLで意味のある文字列をエスケープして、SQLに組み込んだ時に無害になるようにする
一応、これで脆弱性を受けるリスクは大幅に減少するが、都度このような記述を考えるのは面倒である。なので、既存のライブラリを使って書くのが一番楽であるのは言うまでもない。