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

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

提问人:Maximilian Travis 提问时间:8/8/2020 更新时间:8/8/2020 访问量:231

问:

如果我有一个 php 文件收到 $_GET['value'],那么我用 sql 注入或代码注入来启动我的 php 文件是否安全

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

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

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

PHP SQL 代码注入

评论

1赞 Progman 8/8/2020
取决于您拥有的值和实际代码,但是是的。如果可以以这种方式限制输入,并且可能的值不能用于代码注入/sql 注入,则保存它。$allowed_values
2赞 WOUNDEDStevenJones 8/8/2020
是的,但不是明确的。这是验证输入的一种形式,是您应该始终做的事情,但从技术上讲,它不会在技术层面上阻止 SQL 注入。例如,如果实际上有一个允许值,则它仍然会被注入,而使用参数实际上不允许 SQL 注入。' or 1=1--
2赞 Jay Blanchard 8/8/2020
你需要养成接受答案的习惯,这有助于你解决问题。您将获得积分,并鼓励其他人帮助您。

答:

4赞 Barmar 8/8/2020 #1

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

3赞 Bill Karwin 8/8/2020 #2

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

例如:

$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 注入。

您不必拥有数组。您不必记得检查 GET 输入是否在数组中。您不必担心引用或逃避。$allowed_values

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

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

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

评论

1赞 Maximilian Travis 8/8/2020
完美的答案。简明扼要。谢谢。
1赞 subhadip pahari 8/8/2020 #3

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

你的代码是这样的:

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

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

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

in_array() 函数将只允许一些预定义的值,您不能选择以 $_GET 的价格接受自定义用户输入,但由于只允许预定义值,因此任何 SQL 命令在 if 语句中都是安全的。

现在以 $allowed_values 数组为例:

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

如果这些数组值中的任何一个具有可能具有潜在 SQL 注入功能的字符串,则会出现问题。但我认为你不会把任何这样的字符串放在数组 $allowed_values 中。(在上面提到的例子中,索引 3,' 105;DROP TABLE mytable;' 可以删除表 mytable )。否则 SQL 命令将是安全的。

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

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 链接: https://www.w3schools.com/php/php_mysql_prepared_statements.asp

评论

0赞 Maximilian Travis 8/8/2020
谢谢帕哈里先生,对我来说,这确实是你和卡文先生之间的纽带,他的回答非常简洁,但涵盖了很多领域,而你的回答在某些方面更详细。每个都有其优点。无法选择。
1赞 subhadip pahari 8/8/2020
简明扼要地说:in_array() 是最安全的东西,但你只接受预定义的输入。如果 “$allowed_values” 数组下没有任何内容,则 if 语句将不会通过。 但是,如果您想在不知道 PUT 是什么的地方获取用户输入: 使用 REGEX 和 PDO-Prepare 静态来保护 sql 注入。