写点什么

加强 Web 应用程序安全:防止 SQL 注入

  • 2023-08-01
    福建
  • 本文字数:2828 字

    阅读完需:约 9 分钟

加强Web应用程序安全:防止SQL注入

数据库在 Web 应用程序中存储和组织数据时起着至关重要的作用,它是存储用户信息、内容和其他应用程序数据的中央存储库。而数据库实现了高效的数据检索、操作和管理,使 Web 应用程序能够向用户提供动态和个性化的内容。然而,数据库和网络应用程序之间的通信不畅可能会导致敏感数据泄露、用户不信任、法律后果和利润损失。本文将探讨导致此类灾难的后端错误配置,并了解如何确保应用程序的安全。

一、什么是 SQL 注入?


SQL 注入(SQLi)是一个漏洞,它允许网络攻击者篡改 Web 应用程序发送给数据库的查询。当应用程序误解了用户的输入并将其视为 SQL 代码而不是字符串时,就会发生注入。因此,恶意用户可以更改预期的查询流,破坏应用程序的逻辑,并获得对其资源的未经授权的访问。


在大多数情况下,当开发人员需要使用依赖于用户输入的参数化查询时,就会出现 SQLi。如果开发人员在将用户输入插入模板之前忘记对其进行适当的清理,就会引入 SQL 注入漏洞。一个经典的 SQL 注入示例是使用纯字符串插值或连接来创建动态查询,如下图所示。网络攻击者可以通过用 SQL 代码替换分页参数中的数字来注入任意 SQL 语句。


动态查询精心制作的字符串插值

二、什么是 ORM 注入?


现在,开发人员很少使用原始 SQL 语句,而是使用称为 ORM 的特殊框架。对象关系映射(ORM)是一种用作两种不同范例之间的适配器的技术:关系(将数据存储在表中)和面向对象(将数据存储在对象中)。ORM 所做的事情之一是在底层生成 SQL 代码。开发人员所要做的就是告诉 ORM 如何去做。


显然,自动生成意味着自动转义用户提供的数据。ORM 确保每个动态参数都像普通字符串一样被处理,除非开发人员特别禁用清理功能。然而,恶意代码的注入仍然是可能的。ORM 注入是一个漏洞,它允许密切协作攻击者强制 ORM 生成对他们有利的 SQL。


考虑下面的例子。这里有一个函数,它应该接受带有多个参数的对象过滤器,例如:


{"email":, ""name": "user"} 
复制代码


ORM 注入


但是,开发人员忘记检查过滤器是否确实是一个对象,以及它是否只包含安全的过滤参数。这样的错误使攻击者能够注入可用于恢复用户密码的恶意过滤器,例如:

“password LIKE '%a%"

三、SQL 注入真的很危险吗?


通常,SQL 注入可以被认为是一个严重的漏洞。在大多数情况下,对网站任何部分的单个 SQL 注入最终都可以扩展到在数据库上运行任何查询,提取和操作其数据。由于数据库通常保存着系统中最敏感的信息,因此允许网络攻击者访问这些信息是毁灭性的。


以下是 SQL 注入如何被利用的简短列表:

  • 远程代码执行(通常通过特殊功能)

  • 读写主机上的文件。

  • 颠覆 Web 应用程序的逻辑

  • 提取敏感数据

  • 操纵数据

  • 拒绝服务

四、哪些类型的 SQL 注入是可能的?


在通常情况下,有三种类型的 SQL 注入:带内注入、带外注入和盲注入。反过来,带内攻击可以是基于联合的或基于错误的,而盲 SQLi 可以是基于布尔的或基于时间的。


五、SQL 注入层次结构


如果攻击者足够幸运,他们可以在后端响应中包含被破坏的 SQL 查询的结果。这被称为带内 SQLi。带内 SQLi 有两种子类型:

1.基于联合的 SQLi:攻击者能够指定他们可以读取的查询输出的位置(列)。

2.基于错误的 SQLi:当应用程序公开 SQL/编程语言错误时,这种类型的 SQLi 是可能的。在这种情况下,攻击者可以分析错误消息/堆栈跟踪,并推断攻击是否成功。


使用 BlindSQLi,网络攻击者无法看到被破坏的 SQL 查询的结果。然而,它们有某种反馈,可以帮助确定是否存在注入。盲 SQLi 有两种子类型:

1.基于布尔的 SQL:攻击者可以使用 SQL 条件语句以某种方式修改服务器的响应。然后,他们可以将这种新的反应与原来的反应进行比较,并确定注入是否有效。

2.基于时间的 SQLi:攻击者可以将数据库的 SLEEP 函数与条件语句结合起来,从而延迟后端响应。然后,他们可以将原始响应时间与新的响应时间进行比较,以确定注入是否成功。


在某些情况下,攻击者可能根本无法从数据库获得任何反馈。在这种情况下,它们可以强制数据库将输出重定向到另一个位置,并尝试从那里读取它。这就是所谓的带外 SQL 注入。例如,他们可以强制数据库将包含敏感信息的 DNS 查询发送到他们控制的 DNS 服务器。或者,它们可以强制数据库将一些数据写入可公开访问的文件中。这种注入会影响许多数据库。

六、减轻 SQLi 时的常见错误


用户不应该试图为 SQL 输入参数提供自己的清理程序。这样做需要深入了解数据库规范和使用它们的经验。最有可能的是,最终会淹没在其他人无法理解的正则表达式中,并且随着数据库的发展,没有人会支持清理程序。


需要记住:攻击者总是试图混淆他们的 SQLi 有效负载,将其偷运到 WAF 和 IPS。有大量的框架可以利用 SQLi,为攻击者提供扭曲有效负载的脚本库。编写自定义混淆处理程序并将其与现有混淆处理程序结合使用也很容易。


考虑一下开发人员在试图净化用户输入时所犯的一些常见错误。


一个常见的误解是,可以通过删除/替换 SQL 查询参数中的空格来避免 SQLi。例如,如果攻击者只能使用一个单词,会造成多大的伤害?但是许多数据库将注释转换为空格,因此“SELECT email FROM user”等于“SELECT/**/email/**/FROM/**/user”,这是一个单词。


使用注释而不是空格的 SQLMap 篡改脚本


通常认为删除引号可以使参数安全,但有时攻击者可以指定另一个特殊字符来定义字符串。例如,PostgreSQL 允许定义包含在双美元符号中的多行字符串。所以“email”等于 $$ email$$。


SQLMap 篡改脚本,使用双美元符号代替单引号


最后但并非最不常见的错误是对数据库关键字进行非递归删除。这也很容易绕过检测,因为攻击者可以在相同的关键字中间插入关键字。因此,经过清理之后,注入仍然存在。例如:

“SELSELECTECT” -> “SELECT”


用于嵌套关键字的 SQLMap 篡改脚本

七、防止 SQL 注入的正确方法


防止 SQLi 的第一步是使用预处理语句。允许用户定义预处理语句也是不可接受的。这里有一个使用 TypeORM 防止 SQL 注入的例子:采用硬编码的模板,并使用这个框架的特性来安全地插入变量:


使用 TypeORM 编写语句


但是仅仅使用 ORM 是不够的。正如前面看到的,业务逻辑缺陷可以允许绕过安全保护措施。SQLi 修正的第二步是显式验证用户输入。如果需要一个数字,可以手动将值转换为数字。如果需要 URL,可以手动将输入字符串转换为 URL。这种方法显著降低了利用 SQLi 的可能性。额外的好处是,将拥有更一致的数据和更少的错误。有许多库可用于声明性验证,例如 express-validator 或 class-validator。


另一件需要记住的重要事情是始终为每个应用程序创建一个专用的数据库用户。仔细阅读有关默认用户权限的文档,并禁用除了对应用程序运行至关重要的功能之外的所有功能。除了数据库管理之外,永远不应该将 DBA 帐户用于其他任何事情。默认情况下,DBA 帐户被授予所有可能的权限。这显著地放大了 SQL 注入的严重性。


最后但同样重要的是,使用 Web 应用程序防火墙或入侵预防系统。它们能够发现并破坏 SQL 注入攻击,甚至有一组流量规则来检测依赖 SQLi 的已知漏洞。当然,使用 WAF 或 IPS 并不是灵丹妙药,因为它们可以绕过检测。然而,这种工具的存在显著提高了进行攻击所需的知识阈值。另外,WAF/IPS 干扰了 SQLi 开发自动化,并提供了比传统工具更好的日志记录。

发布于: 2023-08-01阅读数: 17
用户头像

IT领域从业者 分享见解 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
加强Web应用程序安全:防止SQL注入_sql_树上有只程序猿_InfoQ写作社区