如何限制现有网站 SQL 注入的影响并降低风险?

信息安全 php sql注入 mysql
2021-08-19 22:05:59

我们的网站 100% 基于 API(带有 SPA 客户端)。最近,一名黑客通过 SQL 注入(并破解 pwd)成功地获取了我们的管理员密码(使用 SHA-256 哈希),如下所示:

https://example.com/api/products?userId=3645&type=sqlinject here

这只是一个例子,但它对我们来说是致命的。幸运的是,这是一个很好的黑客,他刚刚给我们发了一封关于黑客攻击的电子邮件。对于一个在其存在 5 年中不断受到攻击的网站来说是幸运的。

是的,我们知道在将数据发送到 MySQL 之前,我们需要在任何地方检查用户输入并正确格式化/转义/准备语句。我们知道,我们正在修复它。但是我们没有足够的开发人员/测试人员来确保它 100% 安全。

现在假设我们有 0.1% 的机会以某种方式被注入 SQL。我们如何让黑客更难找到它并尽可能限制损害?

到目前为止,我们所做的快速修复/附加测量:

  1. 在所有 API 共享的输出“门”处,我们不再像以前那样发送原始 PDOException 和消息。但是我们仍然必须告诉客户端发生了异常:

    {type: exception, code: err643, message: 'contact support for err643'}
    

    我知道如果黑客看到异常,他会继续尝试......

  2. PHP 用来连接 MySQL 的用户只能对表进行 CRUD。这足够安全吗?

  3. 重命名所有表(我们使用开源,因此黑客可以猜测表名)。

我们还应该做什么?

更新:由于有很多评论,我想提供一些侧面信息

  1. 首先,这是 LEGACY 应用程序,由一些类似学生的人开发,而不是企业级。开发团队无处可寻,现在只有 1-2 个混合开发测试人员处理数百个数据访问类。
  2. 密码是用 SHA-256 散列的,是的,很糟糕。我们正在将其更改为推荐的 php 方式。
  3. SQL注入已经17岁了。为什么它还在?
  4. 准备好的语句对 SQL 注入是否 100% 安全?
4个回答

不要在变通方法或半修复上花费大量时间。您尝试实施此处建议的任何内容的每一分钟,都是您可以花费实施准备好的语句的一分钟。这是唯一真正的解决方案。

如果您有 SQLi 漏洞,那么无论您如何尝试减慢攻击者的速度,攻击者最终都可能获胜。因此请注意,尽管您可能会做出改进,但最终您会输掉比赛,除非您解决问题的根本原因。

至于你到目前为止所尝试的:隐藏错误消息是一个好的开始。我建议您应用更严格的权限(见下文)。更改表名是否有帮助是有争议的,但可能不会受到伤害。

好的,那么这些权限呢?尽可能将数据库用户可以做的事情限制到表甚至列级别。你甚至可以创建多个数据库用户来锁定更多的东西。例如,仅在您实际编写时才使用具有写入权限的数据库用户。仅当您实际需要读取密码列时,才与有权读取密码列的用户连接。这样,如果您在某些其他查询中存在注入漏洞,则无法利用它来泄漏密码。

另一种选择是使用 Web 应用程序防火墙 (WAF),例如 Apache 的 mod_security。您可以将其配置为阻止看起来可疑的请求。但是,没有 WAF 是完美的。而且配置它需要时间和精力。您最好利用这段时间来实现准备好的语句。

再说一次,不要让任何这些引诱你产生虚假的安全感。解决问题的根本原因是无可替代的。

唯一正确的方法是使用准备好的语句。

  1. 如果你伪装错误信息,它会有点困难,但不会阻止攻击者。
  2. 您可以限制权限,但授予用户的所有权限都可能被攻击者获得。在某些情况下,也可以从 SQL 注入执行 shell 命令。
  3. 重命名表对您没有帮助。该工具sqlmap将逐个字符地为您强制使用表名。这不需要太多时间。

您也可以限制呼叫次数,以使攻击者更难攻击或对可疑呼叫发出警报并停止本手册,但解决此问题的唯一正确方法是使用准备好的语句。只需 grep 浏览您的源代码并查看具有动态内容的 SQL 语句并替换它们。

我们知道,但我们没有足够的开发人员/测试人员来确保它 100% 安全。

这是真正的问题除非您雇用更多人或重新分配优先级,否则您并不安全。阻止 99.9% 的攻击者意味着您的数据已被泄露。创可贴解决方案是一件坏事,而且它们不起作用当您可以解决实际问题时,不要浪费时间重构您的 SQL 访问模式。

至于代码解决方案,就像这里很多人建议的那样,使用准备好的语句是安全使用 SQL 的最简单方法。

这比尝试使用 php 自己清理参数要容易得多,而且花费的时间要少得多。只需 grep 您的整个代码库以获取与 SQL 相关的所有内容并修复它。

永远清除代码中的所有 SQL

此问题的最佳解决方案是将所有 SQL 代码作为文字字符串从您的代码中删除,并且不再引入它。相反,请使用诸如 Hibernate 或 Entity Framework 之类的ORM软件。无论如何,这个软件比原始 SQL 好用得多,并且当它最终进入数据库时​​会自动参数化你的 SQL。如果可能,请制定此政策。

如果您没有时间学习和实施这些包,或者由于其他原因无法使用它们,那么 trietend 的答案是下一个最佳选择,使用准备好的语句这将使您免受 SQL 注入的影响。也就是说,除非您向开发人员施加任何压力以提供快速解决方案,否则他们可能会再次忘记参数化单个变量,从而使您回到起点。