PHP - 具有未知数量参数的安全 PDO 准备语句
Posted
技术标签:
【中文标题】PHP - 具有未知数量参数的安全 PDO 准备语句【英文标题】:PHP - secure PDO prepared statement with an unknown number of parameters 【发布时间】:2018-02-20 22:44:36 【问题描述】:*我在 mysqli 或 PDO 的边缘案例中看到了关于这个主题的问题,但没有找到这个特定的问题(这让我感到惊讶,但也许我不知道如何搜索)
在尝试使用 PDO 之前,我使用了简单的、不受保护的查询。我的准备函数看起来像这样,经过简化:
static function prepareUpdate($table, array $arguments, array $filter)
$argumentsList = self::associateArguments($arguments);
$filterList = self::associateArguments($filter);
$query = "UPDATE `$table` SET $argumentsList WHERE $filterList;";
return $query;
$arguments 和 $filter 是关联数组:例如,['name' => 'John', 'occupation' => 'Carpenter']
用于 $arguments,['employeeId' => 518]
用于过滤器。假设 $table 是“工人”。通过一些简单的函数,就变成了:
argumentsList 变成
`name` = 'John', `occupation` = 'Carpenter'
filterList变成
`employeeId` = 518
所以最后的字符串变成:
UPDATE `workers` SET `name` = 'John', `occupation` = 'Carpenter' WHERE `employeeId` = 518;
这对我来说似乎很简单。然后,我尝试在 PDO 的准备语句中使用类似的逻辑。但是我遇到了麻烦。也许是因为我不了解它背后的预期哲学?或者只是技术细节。
如果我理解正确的话,PDO 需要在 prepare() 之后使用 bindValue() 等方法来防止注入。而且,我必须使用占位符(:name、:occupation 等)。
问题是,如果我不知道要查找哪些列,甚至不知道要查找多少列,我该怎么做?
我看到的大多数示例都包含一个非常预定义的语句:UPDATE tableX SET `name` = :name WHERE `id` = :id - 或类似的内容。
如果我想使用可变数量的参数怎么办?我的理解是,我只能用一个属性替换一个 :placeholder,而不是更多(因此不需要引号),所以我不能完全写出类似的东西:
UPDATE :table SET :allParametersHere ;
我该怎么做呢?我没有要在其上使用此函数的明确表,更不用说要检查的有效列的合理列表。我将如何创建一个可以处理不同参数数量的包装器?
【问题讨论】:
您是否尝试过这里的任何答案? ***.com/questions/12344741/… -- 看起来很有希望 几乎@Drew 这个答案:***.com/a/23298742/1194525 由于您使用的是 PDO,因此无需使用bindParam
或 bindValue
:只需将标记的值数组传递给 execute
方法即可。
@aendeerei Dwarf 的模板有问题,用于可变数量的参数,而不是绑定。
相关:An SQL injection against which prepared statements won't help
【参考方案1】:
对于此类问题,database query builder
的解决方案会更好。
回到问题:你知道参数的数量,所以你可以创建查询模板。
<?php
$wq = $pq = [];
$allowed_keys = ['name', 'occupation', '...'];
foreach ($arguments AS $key => $value)
if(in_array($key, $allowed_keys))
$pq[] = "$key = :$key" ;
else throw new Exception('Go away hacker!');
foreach ($filter AS $key => $value)
if(in_array($key, $allowed_keys))
$wq[] = "$key = :$key" ;
$q = "UPDATE $table SET ". join(', ', $pq);
if(!empty($wq))
$q .= 'WHERE '. join(' AND ', $wq);
在结果中,您会得到如下查询模式:
UPDATE workers SET name = :name, occupation = :occupation WHERE employeeId = :employeeId;
允许这样的折叠(如果你有这些表的“安全”密钥)
$allowed_keys
或更好的$allowed_column_names
【讨论】:
我试图做这样的事情,但你的解决方案更优雅。谢谢你的回答。我的问题是,这是否会损害此 PDO 的安全性,因为 $key 变量不会被转义?当然,从技术上讲,它应该来自开发人员,因此应该受到信任,但我有点假设一切都需要安全。除非我们手动转义它。不信任自己的代码听起来很有趣,但如果这是一个接口原型,例如呢? @DwarfVader 只需确保它来自开发人员,或者更确切地说,来自代码。从代码中预定义的列表中获取被认为足够安全的密钥。尽管您仍然可以格式化标识符。如果键基本上是由用户定义的,例如条件 UPDATE 或 WHERE,只需再次将它们过滤掉,against a predefined and hardcoded list 但这还是让人有点失望。你有没有想过使用 ORM?然后代码可能如下所示:Model::factory('Workers', ['employeeId' => 518])->values($arguments)->save()
(来自 Kohana 的示例 docs.koseven.ga/guide/orm/examples/validation)以上是关于PHP - 具有未知数量参数的安全 PDO 准备语句的主要内容,如果未能解决你的问题,请参考以下文章