什么是 SQL 注入?

通过使用 SQL 注入,攻击者可以在受害者的 SQL 数据库上执行未经授权的数据库命令。

Share facebook icon linkedin icon twitter icon email icon

SQL 注入

学习目标

阅读本文后,您将能够:

  • 定义 SQL 注入
  • 解释 SQL 注入的工作方式
  • 了解如何防御 SQL 注入
  • 探索复合 SQLI 攻击

什么是 SQL 注入 (SQi)?

结构化查询语言 (SQL*) 注入是一种代码注入技术,用于修改或从 SQL 数据库检索数据。通过在输入字段中插入专用的 SQL 语句,攻击者可以执行命令,以允许从数据库中检索数据、破坏敏感数据或执行其他操纵行为。

通过正确执行 SQL 命令,未经授权的用户可以伪造特权更高的用户的身份,使自己或其他人成为数据库管理员,篡改现有数据、修改事务和余额以及检索和/或销毁所有服务器数据。

在现代计算中,SQL 注入通常是通过将恶意 SQL 查询发送到由网站或服务提供的 API 端点而在 Internet 上发生的(下文会详细介绍)。在最严重的形式下,SQL 注入可以使攻击者获得对计算机的 root 访问权限,完全掌握控制权。

*SQL 是用于维护大多数数据库的编程语言。

SQL 注入攻击的工作原理

想象一个法庭,一个名叫 Bob 的男子受审,他即将在法官面前出庭。在庭审前填写文书时,Bob 将自己的名字写成“Bob 可以自由离开”。当法官审理其案件并大声读出“下面传唤的人是‘Bob 可以自由离开’”时,法警放开 Bob,因为法官说他可以自由离开了。

尽管 SQLi 的各个变版略有不同,但核心漏洞本质上是相同的:本应为特定类型的数据(例如数字)保留的 SQL 查询字段传递了意外的信息(例如命令)。该命令在运行时越过预期的范围,从而允许可能有害的行为。查询字段通常由在网页上输入表单的数据填充。

我们来简单比较一下普通和恶意 SQL 语句:

普通 SQL 查询:

在此常规 SQL 查询中,studentId 字符串传递到 SQL 语句中。目的是在学生列表中查找与输入的 studentId 相匹配的学生。找到后,学生的记录将被返回。简而言之,命令说“去找到这个用户并给我他们的数据”。

代码可能如下所示:

studentId = getRequestString("studentId");
lookupStudent = "SELECT * FROM students WHERE studentId = " + studentId

如果学生在标有“请输入您的学生 ID 号码”的网页表格中输入 117 的学生 ID,

normal form field

生成的 SQL 查询将类似于:

SELECT * FROM students WHERE studentId = 117;

此命令将返回具有特定 studentId 的学生的记录,这也是符合编写 API 的开发人员期望的。

SQL 注入查询:

在此示例中,攻击者在输入字段中输入 SQL 命令或条件逻辑,他输入的学生 ID 编号为:

SQL injection example form field

通常查询将在数据库表中搜索匹配的 ID,但现在它会查询 ID 或进行测试以查看 1 是否等于 1。正如您所认为的,该列中针对每个学生的语句始终为 true,而因此,数据库会将学生表中的数据所有返回给进行查询的攻击者。

SELECT * FROM students WHERE studentId = 117 OR 1=1;
SQL injection infographic

SQLi 通过针对易受攻击的应用程序编程接口或 API 起作用。在这种情况下,API 是服务器通过其接收和响应请求的软件接口。

有一些常用的工具允许恶意行为者自动搜索网站以查找表单,然后尝试输入各种 SQL 查询,生成网站的软件开发人员计划外的响应,从而供他们利用数据库。

SQL 注入很容易实施,有趣的是,如果采取适当的开发实践,它也很容易防止。现实情况比较含混,因为期限紧迫、开发人员缺乏经验以及遗留代码等情况常常导致代码质量和安全实践参差不齐。可以访问数据库的网站上如果有任何表格或 API 端点上有一个易受攻击字段,就足以形成漏洞。

如何防止 SQL 注入攻击?

有许多方法可以减少由于 SQL 注入而导致数据泄露的风险。作为最佳实践,应采用多种策略。我们来探索一些比较常见的实施:

  • 使用准备好的语句(带有参数化查询) - 这种清理数据库输入的方法需要强制开发人员首先定义所有 SQL 代码,然后仅将特定参数传递给 SQL 查询;输入的数据明确地给出有限范围,无法扩展。这使数据库可以区分输入的数据和要运行的代码,而无论输入字段中提供的数据类型如何。一些对象关系映射 (ORM) 库通常用于此目的,因为某些版本会自动清理数据库输入。
  • 对所有用户提供的输入进行转义 - 编写 SQL 时,特定字符或单词具有特定含义。例如,“*”字符表示“任意”,而单词“OR”表示条件性。为了避免用户意外地或恶意地将这些字符输入数据库的 API 请求中,可以对用户提供的输入进行转义。对字符转义是告诉数据库不要将其解析为命令或条件、而是将其视为文字输入的方式。
  • 使用存储的程序 - 尽管存储的程序本身并不是一种可靠的安全策略,但它有助于限制与 SQL 注入相关的风险。通过适当地限制运行 SQL 查询的数据库帐户的权限,即使容易受到 SQL 注入攻击的非鲁棒性应用程序代码也将缺少操作无关数据库表所必需的权限。存储的程序还可以检查输入参数的类型,以防止输入的数据不符合该字段旨在接收的类型。在静态查询不足的情况下,通常应避免使用存储的程序。
  • 实施最低特权 - 通常,在网站需要使用动态 SQL 的所有情况下,必须通过将权限限制为执行相关查询所需的最窄范围来降低 SQL 注入的风险。最明显的情况就是管理帐户在任何情况下都不应由于来自未授权请求的 API 调用而执行 SQL 命令。虽然存储的的程序最适合用于静态查询,但是强制执行最低特权有助于降低动态 SQL 查询的风险。

什么是复合 SQL 注入攻击?

为了规避安全措施,聪明的攻击者有时会对目标网站实施多媒介攻击。尽管单次的攻击可以防护,但它也可能成为数据库管理员和信息安全团队关注的焦点。DDoS 攻击DNS 劫持和其他破坏方法有时被用作干扰手段,用于掩盖清扫 SQL 注入攻击的实施。因此,全面的威胁防护策略才能提供最广泛的保护。Cloudflare 的 Web 应用程序防火墙DDoS 防护 DNS 安全是整体安全策略的核心要素。