通过准备和执行避免SQL注入

ein*_*180 3 perl sql-injection dbi

一行代码像

my $sql_query = "SELECT * FROM Users WHERE user='$user';";
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

这真的有效吗?如果是,我的所作所为有什么区别吗?优点和缺点是什么?

Bil*_*win 6

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

这将不起作用,因为它正在搜索文字'?'字符-而不是参数。如果您尝试为参数发送一个值,MySQL将会像是“您希望我对此做些什么?” 因为查询没有参数占位符。

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

my $sth = $dbh->prepare("SELECT * FROM Users WHERE user=?");
Run Code Online (Sandbox Code Playgroud)

下一个例子:

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

那将运行查询,但是并不安全。您可以准备任何没有参数的查询。

使用prepare()不是使查询免于SQL注入安全的原因。更安全的方法是使用参数来组合动态值,而不是像本例中那样进行字符串连接。

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

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