PHPのPDOでSQLインジェクション対策を行う方法について確認しました。
※目次をクリックすると目次の下部にコンテンツが表示されます。
PDOでquoteメソッドを使ってエスケープ
●危険なコードの例
<?php require("dbinfo.php"); $id = $_GET['id']; $name = $_GET['name']; $dsn = 'mysql:host=localhost;dbname='.$database.';charset=utf8'; try { $dbh = new PDO($dsn, $username, $password,array(PDO::ATTR_EMULATE_PREPARES =>false,PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`")); } catch (PDOException $e) { exit('データベース接続失敗。'.$e->getMessage()); } $sql = sprintf("SELECT id,name FROM s_table WHERE id = '%s' AND name = '%s'",$id,$name); $st = $dbh->query($sql); echo json_encode($st->fetchAll(PDO::FETCH_ASSOC)); ?>
それぞれのパラメータに下記のような値が入力されるとすべての情報が取得されてしまいます。
id = 12345
name = “‘ OR ‘A’ = ‘A”
●エスケープ処理で対処
下記のように入力パラメータをquoteメソッドでエスケープ処理します。
$sql = sprintf(“SELECT id,name FROM s_table WHERE id = %s AND name = %s”,$dbh->quote($id),$dbh->quote($name));
プリペアドステートメントを使ってSQL実行
require("dbinfo.php"); $id = $_GET['id']; $age = $_GET['age']; $dsn = 'mysql:host=localhost;dbname='.$database.';charset=utf8'; try { $dbh = new PDO($dsn, $username, $password, array( PDO::ATTR_EMULATE_PREPARES =>false, PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`" ) ); } catch (PDOException $e) { exit('データベース接続失敗。'.$e->getMessage()); } $st = $dbh->prepare('SELECT id,age FROM s_table WHERE id = :id AND age = :age'); $st->bindValue(':id', $id , PDO::PARAM_STR); $st->bindValue(':age', $age, PDO::PARAM_INT); $st->execute(); echo json_encode($st->fetchAll(PDO::FETCH_ASSOC)); ?>
●コードの説明
①PDO::prepare
・PDOStatement::execute()メソッドによって、実行されるSQLステートメントを準備
・SQLステートメントは、文が実行されるときに実際の値に置き換えられる0個もしくはそれ以上の名前(:name)もしくは疑問符(?)パラメータマークを含むことができる
②PDOStatement::bindValue
・プリペアドステートメントで使用するSQL文の中で、対応する名前あるいは疑問符のプレースホルダに値をバインドします。
③PDOStatement::execute
・プリペアドステートメントを実行