在没有参数化查询的情况下防止PHP中的SQL注入


Preventing SQL Injection in PHP without parameterized queries?

我知道这个话题已经被讨论到死了,但是我想从社区中得到一些关于我们web应用程序安全性的反馈。

我们有标准的LAMP堆栈web应用程序,其中包含使用mysqli_query执行的大量数据库查询。这些查询目前没有参数化,但是使用addslashes对输入进行了一些简单的转义。

我的任务是使这个系统更安全,因为我们将很快进行渗透测试。上述高层知道参数化查询是使系统更安全的方法,但他们不想花费时间和精力重写应用程序中的所有查询,也不想改变我们必须使它们正常工作的框架。

基本上我在问我有什么选择?

我在输入端运行了mysqli_real_escape_string。我设置了一个过滤器,它不允许像SELECT, WHERE, UNION这样的词被传递,我想这让它更安全。我知道mysqli_query只允许一次运行一个查询,所以那里有一些安全性(从连接更新到选择的结束)。

我这里还有其他选择吗?

编辑:我可能应该补充说,如果有人能够提供一个攻击的例子,这是完全不可避免的没有参数化查询,这也将是有帮助的。我们有一个像这样的查询:

SELECT
pl.created
p.LoginName,
pl.username_entered,
pl.ip_address
FROM loginattempts pl
LEFT JOIN people p ON p.PersonnelId = pl.personnel_id
WHERE p.personnelid = $id
AND pl.created > $date1
AND pl.created < $date2

我已经将UNION查询替换为$id UNION SELECT * FROM p WHERE 1 = 1之类的东西,我可以通过不允许SELECT/UNION来防止这种情况,但我确信还有无数其他类型的攻击我无法想到。谁能再提几个建议?

我已经说服了我的上级,我们需要将查询重写为参数化语句。他们估计可能需要几个月的时间,但这是必须要做的。赢了。我的想法吗?

更新2

不幸的是,我还没能说服当权者,我们需要将所有的查询重写为参数化的查询。我们提出的策略是测试每个输入,如下所示:

如果用户提供的输入为is_int,则将其强制转换为is_int。实数也是一样。在字符数据上运行mysqli_real_escape_string。将查询中的所有参数更改为引号字符串,即

WHERE staffName = ' . $blah . '

根据这个答案,我们是100%安全的,因为我们没有在任何时候改变字符集,我们一直使用带有latin1字符集的PHP5.5

更新3

这个问题被标记为重复,但在我看来,这个问题仍然没有得到回答。根据更新编号。我们发现一些强烈的意见,mysqli_real_escape string函数可以防止攻击,显然是"100%安全"。从那以后,就没有一个好的反驳论据(例如,一个攻击的演示,如果使用得当,可以击败它)。

  • 检查每个用户输入的数据类型和适用的正则表达式(黄金法则是:永远不要相信用户输入)
  • 使用预编译语句
  • serious: prepared statements:)

这需要大量的工作,特别是当你的应用程序处于糟糕的状态时(就像你的情况一样),但这是拥有一个体面的安全级别的最好方法

另一种方式(我建议反对)可能是使用mod_security或WAF来过滤注入尝试的虚拟补丁,但首先要做的是:尝试编写健壮的应用程序(虚拟补丁似乎是一种懒惰的修复方法,但实际上也需要大量的工作和测试,应该只在已经很强大的应用程序代码上使用)

我这里还有其他选择吗?

。没有任何外部措施,比如你试图实施的措施,被证明有任何帮助。您的网站仍有漏洞。

我在输入上运行了mysqli_real_escape_string

恭喜你,你刚刚重新发明了臭名昭著的magic_quotes特性,这个特性被证明是无用的,现在已经从语言中被驱逐了。

jffyi, mysqli_real_escape_string与SQL注入无关。

此外,将它与现有的addslashes()调用相结合,您正在破坏数据,其中的斜杠数量加倍。

我已经设置了一个过滤器,我想这会使它更安全。

它不是。SQL注入不是添加一些单词。

同样,这种方法被称为"黑名单"。事实证明它本质上是不可靠的。黑名单本质上是不完整的,不管有多少"建议"。

我知道mysqli_query只允许一次运行一个查询,所以这里有一些安全性

没有。SQL注入不是添加另一个查询。


为什么我把这个问题关闭为"如何在PHP中防止sql注入?"的副本?

因为这些问题是互斥的,不能在同一站点上共存。

如果我们同意唯一正确的答案是使用预处理语句,那么问题就来了:"我怎样才能避免使用无预处理语句";这没什么意义。

同时,如果OP设法迫使我们给出他们迫切想要的肯定答案,它将使其他问题过时。如果没有准备好的语句,为什么要使用准备好的语句呢?

另外,这个问题也太局部化了。它寻求的不是洞察力,而是借口。除了执政官,谁也不能找借口。一个借口,让他们使用一种被证明是不安全的方法。虽然这取决于他们,但这使得这个问题对社区来说基本上毫无用处。