单引号过滤是废话吗?

信息安全 渗透测试 sql注入 验证
2021-08-19 22:14:54

渗透测试人员发现我们允许在提交的数据字段中使用单引号,并希望我们应用规则(输入验证)以不允许它们出现在任何值中。

虽然我知道单引号在 SQL 注入攻击中很流行,但我强烈反对不应允许它们作为有效输入。我主张通过使用准备好的语句(正确引用值)来实际防止 SQL 注入,而不是过滤掉任何看起来像 SQL 片段的东西。

我的情况:

  • 人名可以包含单引号(例如O'Reilly
  • 文本字段可以包含单引号(例如I'm pretty sure
  • 数字字段可以包含单引号 ( EUR 1'000'000 )
  • 还有很多

我见过其他情况,应用 SQL 注入预防规则出于最愚蠢的原因丢弃了有效数据(名称“ Andreas ”被拒绝,因为它包含AND,纯文本字段中的各种常用词被拒绝,因为它们包含关键字“ select ”, “插入”、“更新”或“删除”)。

安全专家对此有何立场?

出于我所说的原因,我们是否应该拒绝对单引号实施输入验证?

4个回答

您应该将输入验证实现为一种纵深防御方法。所以输入验证不应该是你对 SQL 注入的主要防御,它应该是准备好的语句。作为额外的防御,您应该限制允许的输入。

这永远不应该限制功能。如果在输入中有撇号的合法用例,您应该允许它。因此,您应该允许在名称字段、描述、密码中使用单引号,但不允许在数字字段、用户名字段、车牌字段中使用单引号。

在所有输入中阻止单引号是疯狂的。这破坏了应用程序的功能,甚至不是针对 SQL 注入的正确解决方案。

考虑一下您误解了渗透测试公司的可能性。如果这真的是他们的建议,那么这对渗透测试公司来说是很糟糕的,我建议你寻找一个有助于正确保护你的软件的渗透测试合作伙伴,而不是让它无法使用。

在注入攻击的情况下,这显然是错误的——您的数据库层正在正确处理字符串,或者没有。由于撇号在名称和自由文本中有效,因此完全阻止它们会破坏应用程序,而有选择地阻止它们不会解决注入问题。

但是严格的输入验证一般原则上的良好实践,并且在撇号不是合法值的一部分的情况下过于宽容是没有意义的。您举了 的示例EUR 1'000'000,这是一种特定于语言环境的格式(仅限瑞士,AFAIK)-但允许格式成为值的一部分在那里没有意义。如果用户输入1,500,您的应用程序应该按原样存储吗?您是否必须在每次处理时决定将其解释为 1.5 还是 1500?在客户端处理特定于语言环境的表示,并在内部以规范形式处理数值会更有意义。

因此,这里的答案将取决于审计是在抱怨有意义的特定领域,还是建议全面禁止撇号。如果是前者,这是一个合理的观点。如果是后者,他们很愚蠢,可能会盲目地遵循清单。

步骤 1) 参数化您的 SQL。

步骤 2) 确保您使用 SQL DB 连接库来设置参数值,不仅仅是内联设置它们。这是对 SQL 注入的实际防御。

步骤 3) 不要在 SQL 中进行查询构建。那就是疯狂。

第 4 步)添加一个配置开关以将错误一直传播回用户。在测试期间打开它。

步骤 5) 告诉你的渗透测试人员找到一种方法来生成带有奇数单引号的 SQL 错误或闭嘴。

我不是保安。我是一名必须维护安全代码的程序员。这就是我所说的“脆弱”实践。入口点分散在一个典型的项目中。找到并清理所有这些需要大量的工作来解决一个问题,需要大量的仔细维护和麻烦,以确保它在代码更改时仍然有效,并且充满了使其无效的假设。

取而代之的是使用更易于维护、分层、上下文相关并解决广泛问题的实践。那么你就不需要昂贵的、过于宽泛的过滤了。

如果您不知道如何使用它们,则无法保护输入。

假设您通过从所有输入中删除所有单引号来“保护”您的系统。太好了,您可以安全地抵御一种SQL 注入攻击。如果该输入用于...

  • 允许双引号的 MySQL 查询
  • 文件系统操作
  • 外壳命令
  • 网络查询
  • 方法名称
  • 班级名称
  • eval

其中每一个都有不同的特殊字符、转义序列、引用规则和安全实践。您无法预测输入时将如何使用它。试图去除所有特殊字符是疯狂的,并且只能“解决”一类攻击。

或者如果允许用户输入页面限制怎么办。在参数化查询中尽职尽责地使用了该限制;没有 SQL 注入,耶!用户进入9999999999,现在您对 DOS 攻击持开放态度。

您必须在执行可能不安全的操作时应用适当的安全措施。这考虑了许多独特的操作因素;清理输入字符只是其中之一。

只要你这样做,你也可以参数化你的查询。然后不再需要做所有的工作和毯子剥离报价的损坏。

过滤所有输入很困难。

在给定的项目中,有很多很多很多方法可以获取和传递输入:

  • 表单输入
  • 网址
  • 文件名
  • 文件内容
  • 数据库查询
  • 网络读取
  • 环境变量

这些通常是非常自由的形式,可以使用许多不同的库。我不知道有任何静态分析工具可以验证所有潜在易受攻击的输入都经过过滤。有些语言有taint系统,但很难有效使用。即使您过滤所有输入,如果没有静态分析工具,未过滤的输入也会随着开发的进行而泄漏回来。维护一个妨碍功能的不完整、昂贵的结果需要付出很多努力。

相反,通常只有一种方法可以在项目中执行 SQL。存在静态和运行时工具来自动检测潜在的 SQL 注入。您甚至可以完全禁止字符串,并要求所有查询都是 SQL 查询对象。这些良好实践易于维护,并且越来越多地融入工具和 SQL 库中。

“防火墙”导致安全性松懈。

类似于某些办公网络因为“我们有防火墙”而具有非常不安全的做法,团队也有可能因为“输入是安全的”而变得懒惰保护他们的代码。输入绝对不安全。

机会成本

有些人可能会说“为什么不两者兼而有之?” 你只有这么多的时间来做一个项目。低效率、高维护的做法是浪费时间。实施和维护它将使您的有限时间远离更高效、更易于维护的做法。在最坏的情况下,您将花费大量时间与输入进行打地鼠游戏,以及由过于激进的过滤引起的后续问题,您将永远没有时间采取适当的安全措施。

简而言之,输入过滤是昂贵的、泄漏的、难以维护的,不能解决问题,并且可能会使情况变得更糟。