in_array 函数是阻止代码 injection/sql 注入的安全方法吗?

Is the in_array function a safe way of blocking code injection/sql injection?

如果我有一个正在接收 $_GET['value'] 的 php 文件,它是否可以安全地防止 sql 注入或代码注入让我开始我的 php 文件

if (in_array($_GET['value'], $allowed_values);) 
{ /* normal page code handling the $_GET['value'] */ 

 } else { unset($_GET['name'])
 }

$allowed values 显然是所有值的数组,我希望它对 $_Get['value'] 是安全的。这还不安全吗?谢谢。

是的,这是一种常见且安全的技术,可用于无法使用查询参数的情况。例如,如果该值将用作 table 或列名,则不能将其作为查询参数提供,您必须将其直接替换为 SQL 字符串。像这样的白名单是确保这是安全的推荐方法。

这取决于 $allowed_values 数组中的值,以及您如何将值插入到 SQL 查询中。

例如:

$allowed_values = [ 'a word' ];

if (in_array($_GET['value'], $allowed_values)) {
  $sql = "SELECT * FROM mytable WHERE id = {$_GET['value']};";
}

绝对不安全。结果是 SQL:

SELECT * FROM mytable WHERE id = a word;

这是语法错误。

为什么不直接使用 SQL 查询参数?那你就不用担心安全不安全了。查询参数将值与 SQL 解析分开,因此任何类型的值都不可能导致 SQL 注入。

您不需要 $allowed_values 数组。您不必记得检查 GET 输入是否在数组中。您不必担心引用或转义。

的确,查询参数仅适用于值,即代替带引号的字符串文字或带引号的日期时间文字或数字文字。如果您需要查询的其他部分是动态的,例如 table 名称或列名称或 SQL 关键字等,请使用您所展示的 allow-list 解决方案。

但是更常见的插入动态值的情况最好由查询参数处理:

$sql = "SELECT * FROM mytable WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt-execute( [ $_GET['value'] ] );

让我们详细讨论一下这件事:

你的代码是这样的:

if (in_array($_GET['value'], $allowed_values);) { 
 ...........
 $sql = "SELECT * FROM mytable WHERE id = $_GET['value']";
 ...........

} 
else { 
  unset($_GET['name'])
}

现在让我们假设,您有一些值:

in_array() 函数将只允许一些 pre-defined 值,您不能选择通过 $_GET 获取自定义用户输入, 但由于只允许 pre-defined 值,任何 SQL 命令在 if 语句中都是安全的。

现在以 $allowed_values 数组为例:

$allowed_values = ['some details' , 'another details' ,3, ' 105; DROP TABLE mytable;', 22 , 'ok'];

如果这些数组值中的任何一个具有可以具有潜在 SQL 注入能力的字符串,那么就会出现问题。但我认为您不会将任何此类字符串放入数组 $allowed_values 中。 (在此 above-mentioned 示例中,索引 3,' 105; DROP TABLE mytable;' 可以删除 table mytable )。否则 SQL 命令将是安全的。

现在您可以通过对任何 SQL 查询使用 PDO,在代码中添加额外的安全层。 (在这个例子中你不需要那个,因为 in_array() 函数是 100% 安全的,除非你自己在数组中放入任何恶意代码,根据我的 above-mentioned 示例)。但是对于其他类型的用户输入,您必须根据用户输入进行一些 SQL 查询,您可以使用 PDO 准备语句。

一个 PDO 示例是这样的:

$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";

$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


$stmt = $conn->prepare("INSERT INTO photos (username, kname) VALUES (?, ?)");
$stmt->execute([  $username , $kname   ]);

有关更多信息,请尝试 w3school link:https://www.w3schools.com/php/php_mysql_prepared_statements.asp