使用PDO::prepare
可能会大大降低SQL注入的可能性,因为它允许参数化查询。但是,由于它还允许非参数化查询,其安全性完全取决于它的使用方式。
对于我相当缺乏经验的编程团队,我考虑在PDO::prepare
上放置一个包含额外级别的过滤器的包装器:如果参数包含任何单引号或双引号,则会生成错误。
现在,在代码检查期间,我们所要做的就是检查每个查询是否使用包装器而不是PDO::prepare
(或任何其他执行查询的函数)。当我们发现违规时,它需要被修复,或者,在极少数情况下,它涉及一个不能由参数处理的动态查询,例如变量列或表名。 (在我们构建的应用程序类型中非常不寻常。)然后可以非常仔细地研究这些少数情况,以确保它们安全。
我的问题是:在声明中排除引号是否会阻止SQL注入非参数化查询,正如我所假设的那样,并且它是一种使代码检查更可靠和有效的实用工具吗? / p>
答案 0 :(得分:4)
不,这不是一个实际的解决方案。在SQL语句中使用引号是有正当理由的,因为字符串文字和日期文字使用引号。没有正当理由在SQL查询中对每个字符串或日期常量使用查询参数。它只会使您的查询不可读,并且在某些情况下会产生性能成本。
SQL注入也有机会与引号无关。如果在没有良好实践的情况下实施,那么形成SQL查询的动态内容(即应用程序变量)的任何部分都有可能变得不安全。
SQL中的数字常量不需要引号。您的过滤功能无法捕获这些情况。
$sql = "SELECT * FROM MyTable WHERE id = $UnsafeVariable";
我与PHP安全专家和作者交谈过,他声称没有查询参数不是解决方案的情况。我向他展示了这个问题:
$sql = "SELECT * FROM MyTable ORDER BY $SomeColumn $AscOrDesc";
当您拥有允许用户选择要对其进行排序的列的用户界面,或单击向上箭头或向下箭头时,这是您在Web应用程序中要执行的操作的一个非常明确的示例选择排序方向。这些是不涉及引号的情况,不能使用预准备语句进行参数化,但如果$SomeColumn
或$AscOrDesc
包含未经验证的内容,它们仍然存在SQL注入漏洞的风险。
制定像你描述的那样的一揽子规则也不实际。总有例外情况。您将花费太多时间查看这些案例并授权开发人员绕过您的过滤功能。 “一刀切”规则的问题在于它们没有。
代码审核是提高代码质量的经济实用的方法。
更好的解决方案是允许开发人员以最实用的方式编写代码,但创建一个每个代码提交通过代码审查的策略。
我们在现有公司这样做。即使是高级开发人员也需要让其他开发人员与他们进行代码审查。我们使用github,我们已经开始练习每个重要的代码更改遵循以下步骤:
这不仅会抓住错误(即使是高级开发人员也会错过一些东西),但向初级开发人员展示更多代码只会提高他们的技能。随着初级开发人员的成长,这会产生乘数效应,因为他们减少了新手错误,他们甚至可以成为高级开发人员来帮助下一组青少年。
答案 1 :(得分:1)
在声明中排除引号会阻止SQL注入吗?
最近我写了一篇文章,除了你应该知道的其他内容之外,它还包含一个 doesn't involve a single quote 的SQL注入工作示例:
<form method=POST>
<input type=hidden name="name=(SELECT password from admins)WHERE`id`=1#" value="">
<input type=hidden name="name" value="Joe">
<input type=hidden name="id" value="1">
<input type=submit>
</form>
<?php
if ($_POST) {
$pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '');
$params = [];
$setStr = "";
foreach ($_POST as $key => $value)
{
if ($key != "id")
{
$setStr .= addslashes($key)." = :".$key.",";
}
$params[$key] = $value;
}
$setStr = rtrim($setStr, ",");
$pdo->prepare("UPDATE users SET $setStr WHERE id = :id")->execute($params);
var_dump("UPDATE users SET $setStr WHERE id = :id", $_POST);
}
这是一种使代码检查更可靠,更有效的实用工具吗?
没有丝毫。