了解PDO准备的语句和绑定参数


Understanding PDO Prepared Statements and Binding Parameters

根据经验以及不断被告知使用准备好的语句和绑定参数的好处,我一直在代码中使用这两种技术,但我想确切地理解这两种方法的目的:

根据我对准备好的声明的理解:

$sql = "SELECT * FROM myTable WHERE id = ".$id;
$stmt = $conn->prepare($sql);
$stmt->execute();

前面的代码应该使用我提出的查询在数据库中创建一种缓冲区。现在根据我的理解(我可能错了),以前的代码是不安全的,因为字符串$sql可以是任何东西,这取决于$id实际是什么,如果$id=1; DROP TABLE myTable;--,即使我有一个准备好的语句,我也会插入一个恶意查询。

根据我的理解这就是绑定我的参数的地方。如果我改为执行以下操作:

$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();

数据库应该准确地知道sql语句的所有部分:SELECT这些列:* FROM myTableWHERE id ="用户输入的变量",如果"a variable that was input by the user" != a variable,则查询失败。

有些人告诉我,我的理解是正确的,而另一些人告诉我这是错误的,有人能告诉我我是错的、正确的还是遗漏了什么吗?如需详细说明,我们将不胜感激!

第一种情况是不安全的,这是正确的。不过,重要的是要理解,只有在使用变量数据和/或重复执行同一查询时,准备语句才有价值。如果您正在执行没有变量的纯语句,您可以简单地执行以下操作:

$sql = "SELECT * from myTable WHERE this_column IS NOT NULL";
$result = $conn->query($sql);

最后得到一个PDOStatement对象,就像使用PDO::exec()一样。

对于你的第二种情况,同样,你基本上是正确的。发生的情况是,传递给数据库的变量被转义并引用(除非您用PDOStatement::bindParam()的第三个参数另行指定,否则它会作为字符串发送,这在大多数情况下都很好。)因此,如果发送了错误数据,查询不会"失败"。它的行为就像您传递了一个在数据库中不作为ID存在的有效数字一样。当然,在某些边缘情况下,即使准备了正确的语句,您仍然很容易受到攻击。

此外,为了让生活更轻松,您可以使用这样的预先准备好的语句来进行隐式绑定:

$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->execute([":id"=>$id]);

甚至像这样,使用未命名的参数:

$sql = "SELECT * FROM myTable WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->execute([$id]);

当然,当我输入答案时,大部分内容都已经在评论中解释过了!