使用 prepare 和 execute 避免 SQL 注入

Avoiding SQL injections with prepare and execute

一行代码如

my $sql_query = "SELECT * FROM Users WHERE user='$user';";

可能会在您的程序中引入 SQL 注入漏洞。为了避免这种情况,可以使用类似

my $sth = $dbh->prepare("SELECT * FROM Users WHERE user='?';");
$dbh->execute($user);

但是,在我目前正在处理的代码中使用了以下代码

$sql_query = "SELECT * FROM Users WHERE user='" . $user . "';";
$dbh->prepare($sql_query);
$dbh->execute();

这真的有效吗?如果是,我会做的事情有什么不同吗?有什么优点和缺点?

my $sth = $dbh->prepare("SELECT * FROM Users WHERE user='?'");

这将不起作用,因为它正在搜索文字 '?' 字符 — 而不是参数。如果您尝试为参数发送一个值,MySQL 会像 "what do you want me to do with this?" 因为查询没有参数占位符。

如果要使用参数,则不得将参数占位符放在 SQL 查询中的字符串定界符内,即使参数将采用字符串或日期时间值:

my $sth = $dbh->prepare("SELECT * FROM Users WHERE user=?");

下一个例子:

$sql_query = "SELECT * FROM Users WHERE user='" . $user . "'";
$dbh->prepare($sql_query);
$dbh->execute();

这将 运行 查询,但它不安全。您可以准备任何查询,即使它没有参数。

使用 prepare() 并不能使查询免受 SQL 注入。使它更安全的是使用参数来组合动态值,而不是像您在此示例中那样进行字符串连接。

但是使用参数确实需要使用prepare()

PS:当您以编程方式一次 运行 一个查询时,您不需要将 ; 放在 SQL 查询的末尾。仅当您 运行 多个查询时才需要分隔符,例如在 SQL 脚本或存储过程中。在您的示例中,; 是无害的,但 MySQL 不需要它,它只会忽略它。