接受原始 SQL 的 HTTP API 的潜在滥用是什么?

信息安全 php sql注入 mysql
2021-09-02 09:16:29

我想知道接受 SQL 查询和输出结果集的 HTTP API 可能存在哪些潜在滥用。这是 SQL 注入的规范定义这一事实对我来说并没有丢失 :)

就我而言,我有一个特定的 PHP/MySQL 应用程序,它是 Magento - 一个电子商务平台。

以下是我考虑过的一些安全措施:

  • 非标准 URL 路由 - 为了防止大规模扫描,每个安装都有自己的 URL 路由(这类似于 Magento 的管理后端的处理方式)
  • 一个相当长的 API 密钥
  • 仅 HTTPS 访问
  • 通过只读 MySQL 用户进行只读访问。
  • 通过 SQL 解析进行只读访问。如果可以以这种方式实现只读访问,则需要更少的配置。我正在考虑简单地解析“INSERT”、“UPDATE”、“DROP”等的查询。
  • 列入黑名单的表和字段。在大多数情况下,配置数据存储在一个名为 的表中core_config_data,因此可以将其列入黑名单。诸如信用卡令牌之类的东西也可以存储在特定表的特定字段中。在非常糟糕的实现中,信用卡也可以明文存储,当然需要将其列入黑名单。
  • 白名单表和字段访问——也许只允许访问白名单表和字段比黑名单更好。
  • 有很多社区扩展也可能存储敏感信息。默认情况下很难普遍阻止它们,所以我认为白名单可能是解决这个问题的唯一选择。
  • 一些最大重试次数/频率的机制
  • 用于保护 SSH 连接的其他标准东西,例如 IP 白名单、公钥认证、VPN 等。

假设这些措施已经到位,这是否会与 IP 白名单锁定的 SSH 访问一样安全或更安全。

更新:应用程序的更多细节,以跟进答案中的一些问题。

  • 我正在寻找构建的东西是一个 Magento 模块,它将被部署到商店并接受 SQL 查询以将数据返回到我的 SaaS 应用程序。我拥有该模块和 SaaS 应用程序。
  • 有问题的应用程序将是一个 SaaS 应用程序,它利用 Magento 提取数据。因此,这不是只有受信任的员工才能访问的情况。
  • 理想的最低安全级别(从配置量的角度来看)是不使用只读用户。
  • 让我们假设将被阻止的误报不是问题(抱歉,“Bobby Insert Tables”)。

更新 2:只是想更详细地说明我选择将这个问题与带有 IP 地址白名单的 SSH 连接进行比较的原因。

用于所有意图和目的的 SSH 连接在功能上已经与原始 SQL API(以及更多)相同,因为您可以通过 SSH 进入并连接到 MySQl,然后做任何事情。所以我的想法是,如果 SQL API 与 SSH 连接一样安全或更安全,它可能会带来可接受的风险水平。

另外,我知道这种类型的问题可能过于主观,所以我想以一种可以有一个相对客观的答案的方式来构建它,这就是为什么我想将它与特定的 SSH 场景进行比较。

3个回答

滥用的可能性显然取决于应用程序。这是否只面对具有特权访问权限的 Intranet/VPN 上受信任的员工?否则这些员工是否拥有对数据库的只读访问权限,因为他们需要在数据上运行大量不同的查询?在这种情况下,我可以想象允许受信任的用户生成任意原始 SQL 查询。

或者这个应用程序是否面临任何可能看到您的在线商店并试图造成严重破坏的随机攻击者?在这种情况下——我强烈建议你不要这样做。花点时间完成工作流程并创建允许运行的参数化查询——HTTP API 的用户仅有权更改这些查询的参数。

将 SQL 命令解析为像UPDATE/这样的坏术语DROP是一个非常糟糕的主意。人们可以非常聪明地绕过这些预防措施(例如,您可以绕过过滤器,<script>通过使用<scr<script>ipt>which then become来删除标签<script>)。同样,某些字段中包含值“更新”可能是有正当理由的。编码问题/unicode 规范化问题可能会绕过您的过滤器。例如,攻击者发送DRO%C0%50的 URL 编码字符串通过了标记为“DROP”的过滤器,但是当字节DRO\xc0P被发送到数据库时,其处理方式与DROP允许攻击者删除数据库相同。(有关更多信息,请参阅目录遍历攻击中使用的这个技巧)。

拥有一个只读帐户是一个更好的解决方案,但同样您可能不希望攻击者能够访问某些私有字段(例如,CC #s、密码哈希等)。此外,创建 CPU 密集型恶意 SQL 命令并不难,可用于对您的数据库进行拒绝服务攻击

让不受信任的最终用户编写代码(并且 SQL 命令就是代码)始终是一种反模式,应该避免。是的,这将需要更多的工作来提出允许的参数化查询,但它非常值得。


编辑:

如果您的应用程序生成的查询始终完全受信任,则这是一个不同的问题。那就是您的应用程序正在生成成对的参数化查询,例如"SELECT name FROM users WHERE id = ?"发送到数据库以及一组不受信任的用户输入 -["1"]或者在 SQL 注入攻击失败的情况下["1 OR 1 = 1; DROP TABLE user; --"])。或者可能更成问题,但可能是安全的,您使用一些现有的众所周知的 SQL 注入清理功能来清理您的输入以发送某些内容。我个人不会冒险第二条路线,但成熟的消毒功能可能能够做到这一点。

然后,您需要做的就是在您的应用程序和 HTTPS API 之间使用经过身份验证的加密(例如,对消息进行加密和 MAC'd)。IP 地址白名单是在整个 TLS 上完成此任务(除了发送密码之外)的一种合理方法(并验证托管 API 的其他服务器的身份以防止中间人攻击)。

大多数数据库(包括 MySQL)旨在安全地支持这种操作模式。这曾经被广泛用于直接访问数据库的“胖客户端”应用程序。这个想法是你给相关用户他们需要的数据库权限,并且数据库控制访问。一些数据库(尤其是 Oracle)支持极其精细的权限,包括行和列级别的控制,以及“虚拟私有数据库”。

如今,胖客户端倾向于直接访问 Web 服务而不是数据库,但类似的模型用于需要运行自定义查询但对数据库只有有限权限的分析人员。

不幸的是,这种方法的安全性在很大程度上受到了质疑。大多数数据库都有许多漏洞,低权限的数据库用户可以提升他们的权限。尤其是甲骨文有几十个这样的漏洞。相比之下,大多数数据库几乎没有允许未经身份验证的远程用户控制数据库的漏洞。

一些安全公司(包括我的雇主)提供工具和服务来提高数据库安全性。但是,架构趋势是使数据库更加私有,并且只能由应用程序服务器访问,这降低了这种安全性的重要性。

如果您真的热衷于按照您的建议去做,那么您的数据库的安全性就变得更加重要。您解析和过滤 SQL 查询的建议有一些优点,但请注意 SQL 解析起来非常复杂。有一些设备(例如 Oracle 数据库防火墙)可以执行此操作,尽管它们并不是真正针对您的场景。

也许您需要一些通用查询 API,但不一定是 SQL?在这种情况下,您可以考虑使用Java Persistence API之类的东西。这可以映射到服务器上的SQL,但是因为比SQL简单,所以出错的可能性较小。

要补充其他人所说的,您不需要数据库表写入权限来安装后门尽管它使用的是 SQL Server 而不是 MySQL,但有人曾经向我展示了一个脚本,该脚本允许通过 SQLI 在服务器上创建新用户(我相信通过向系统发起攻击,不记得了)。

如果您确实需要灵活的数据访问,我会研究一些 OData 包装器,它通过不运行任意 SQL 来保护数据库,但足够灵活以支持各种查询。

我确实看到了应用程序在他们的 HTML 中发送了 SQL(我相信是 facebook),但是他们发送它是经过签名的,所以如果它不是来自他们,他们就不会接受返回的 sql。这意味着没有人可以在不破坏签名的情况下更改它,他们会拒绝请求。