在 MySQL 中使用绑定参数作为用户定义变量是否安全?

mic*_*all 3 php mysql pdo sql-injection prepared-statement

问题

我知道使用准备好的语句可以防止注入,因为准备好的语句执行由两个阶段组成:准备和执行

好的,但我真的不明白如果将绑定参数值用作MySQL 中的用户定义变量会发生什么情况。

最初安全绑定的参数过程是否可以用于步骤 2 中的执行(以及注入)?

// The user input that may be the target for injection
$userInput = "input";

// STEP 1 -------------------
$q = "SET @param1 = :param1;";  

// Execute query to set mysql user-defined variables
$param = [
'param1'    => $userInput
];

$stmt = $pdo->prepare($q);
$stmt->execute($param);


// STEP 2 -------------------
// Query DB with User-Defined Variables
$q = "
SELECT ...
WHERE 
table.field1 = @param1 OR
table.field2 = @param1 OR
table.field3 = @param1
";

// Query
$stmt = $pdo->query($q);


// STEP 3 -------------------   
// Fetch Data
$row = $stmt->fetch();
Run Code Online (Sandbox Code Playgroud)

我为什么要使用这种方法?

我用它来避免多个类似的命名参数,如下例所示

您不能在准备好的语句中多次使用同名的命名参数标记,除非启用了模拟模式

来自手册。对于复杂的查询来说,维护起来很混乱:

$q = "
SELECT ...
WHERE 
table.field1 = :param1_1 OR
table.field2 = :param1_2 OR
table.field3 = :param1_2
";

$param = [
'param1_1'  => $userInput
'param1_2'  => $userInput
'param1_3'  => $userInput
];

$stmt = $pdo->prepare($q);
$stmt->execute($param);
Run Code Online (Sandbox Code Playgroud)

Bil*_*win 5

是的,您可以假设用户变量代替查询中的单个标量值,就像绑定参数占位符一样。这是针对 SQL 注入的有效保护。

证明:尝试使用用户变量执行 SQL 注入。

SET @s = 'Robert''; DROP TABLE Students;--';

SELECT * FROM Students WHERE name = @s;
Run Code Online (Sandbox Code Playgroud)

这不会删除表。它可能什么也没有返回,因为没有学生有那么奇怪的长名字(除非你和Little Bobby Tables一起上学)。


但是,我想知道是否有这样的查询:

SELECT ...
WHERE 
table.field1 = @param1 OR
table.field2 = @param1 OR
table.field3 = @param1
Run Code Online (Sandbox Code Playgroud)

指示 field1、field2 和 field3 实际上应该是子表中的单个字段。如果您在多个列中搜索相同的值,则它可能是一个重复组。例如,如果是phone1、phone2、phone3,则这是一个多值属性,应存储在子表中多行的一列中。然后您可以使用单个参数进行搜索。