2

我正在尝试将访问者的输入插入数据库。
这行得通,但是 - 这足以防止 sql 注入吗?

<?php
$db_host = "localhost";
$db_name = "db_qadenza";
$db_user = "root";

$odb = new PDO ("mysql:host=" . $db_host . ";dbname=" . $db_name, $db_user);

if(isset($_POST['Submit']))
{
$user = $_POST['user'];
$pass = $_POST['pass'];
$mail = $_POST['mail'];
$confirm_key=md5(uniqid(rand()));

$q = "INSERT INTO members (user, pass, mail, confirm_key)
VALUES(:user, :pass, :mail, :confirm_key);";

$query = $odb->prepare($q);
$results = $query->execute(array(
":user"=>$user,
":pass"=>$pass,
":mail"=>$mail,
":confirm_key"=>$confirm_key,
));

exit();
}
?>
4

3 回答 3

4

您的代码有两个问题。

  1. 您正在使用模拟的准备好的语句。这是 PDO_MYSQL 驱动程序的默认行为。为了规避它,您应该添加:

    $odb->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    

    结合缺少用于与 DB 通信的字符集,这会使您的代码容易被注入。要建立连接,您应该使用:

    $odb = new \PDO('mysql:host=localhost;dbname=******;charset=UTF-8', 
                    'user', 'pass');
    
  2. 您的密码散列方法不安全(或者实际上不存在)。相反,您应该为每个密码使用crypt()带有CRYPT_BLOWFISHPBKDF2和不同盐的函数。

此外,您可能会考虑使用bindParam()设置命名参数的方法,因为通过设置它们execute()会将值绑定为PDO::PARAM_STR,但还有其他选项,您可能会觉得有用。

于 2012-08-04T05:02:55.907 回答
2

是的。prepare($query)方法确保不会发生sql 注入,只要将用户定义的值作为传递的变量输入,它们是给你的。

从链接页面:

如果应用程序专门使用预准备语句,开发人员可以确保不会发生 SQL 注入 [...]

于 2012-08-04T04:54:31.883 回答
1

是的。我觉得很好。

如果您愿意,您还可以创建额外的 mysql 用户来限制 SQL 注入事件的范围。目前,您正在以root.

还要考虑使用密码散列方案,例如 salt + BCrypt。

于 2012-08-04T04:56:39.197 回答