@blog.justoneplanet.info

日々勉強

PHP Database Security(データベースのセキュリティ)

すなわちSQLインジェクションのための防御策である。

■SQLインジェクションの実例

以下のログインフォームで考える。

<form method="post" action="login.php">
Name: <input type="text" name="name" />
Password: <input type="password" name="password" />
<input type="submit" />
</form>

以下のコードで存在するユーザかどうか、DBに問い合わせて検証する。

<?php
$password = md5($_POST['password']);
$sql = "SELECT * FROM `user` WHERE `name` = '{$_POST['name']}' AND `password` = '{$password}'";
?>

一見、何の問題も無いようだが、Nameに「1′ OR 1 = 1 –」とすると以下のSQL文を実行することになる。

SELECT * FROM `user` WHERE `name` = '1' OR 1 = 1 --' AND `password` = 'password_str'

「–」以降は改行コードまで全てコメントとみなされ、条件「`name` = ‘1’」は殆ど成立しないが、条件「1 = 1」が常に成立し、全てのユーザデータが返ることになる。従って、アルゴリズムにもよるが、ログインが常にできてしまう。

対策1

以下のように、プリペアドステートメントを用いる。

<?php
try {
    $dsn = 'mysql:host=localhost;dbname=db';
    $dbh = new PDO($dsn, DB_USER, DB_PASS);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
}
catch(PDOException $e){
    //code
}
$password = md5($_POST['password']);
$sql = "SELECT * FROM `user` WHERE `name` = ? AND `password` = ?";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
    $_POST['name'],
    $pasword
));
$result = $stmt->fetchAll();
?>

対策2

以下のように、エスケープ処理を忘れずに行う。

$dbh = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_NAME, $dbh);
$password = md5($_POST['password']);
$name = mysql_real_escape_string($_POST['name']);
$sql = "SELECT * FROM `user` WHERE `name` = '{$name}' AND `password` = '{$password}'";

但し、ログインフォームなので大概において英数字のユーザ名なのでフィルタリングすることをお勧めする。

コメントはまだありません»

No comments yet.

RSS feed for comments on this post.TrackBack URL

Leave a comment