SQL 注入(简称 SQLi)是黑客手册里最古老的招数之一,但至今仍然极其常见且危险。简单说,它就是诱使数据库泄露本不该公开的信息。
本文将带您了解 SQL 注入究竟是什么、攻击者如何利用它、一些造成严重损失的真实案例,以及更重要的——如何防止它发生。无论您是开发者还是对互联网漏洞机制感兴趣,读完后都能对 SQLi 有扎实的认识(而且不会读到一半睡着,我保证)。
什么是 SQL 注入?
SQL 注入是一类攻击:当有人设法篡改您的应用发送到数据库的 SQL 查询时就会发生。通常,这些查询用于获取用户资料或更新商品信息。但通过 SQLi,攻击者可以将恶意的 SQL 代码注入输入字段(如搜索框或登录表单),然后数据库就会按他们的意愿行事。
为什么会奏效?
因为在某个环节,应用过度信任了用户输入,把它当作无害文本,而不是潜在可执行代码。就像让人填一张表,然后把他们写的内容直接粘贴进命令行一样。
为什么危险?
SQL 注入的危险在于,它可被用来查看或窃取私人数据(如用户名、密码或信用卡信息)、绕过登录界面、删除或修改数据,最糟情况下甚至完全控制数据库服务器。
总之,SQLi 很糟糕,而且也不是最近才出现的安全问题,但您会惊讶有多少应用至今仍未妥善防护。
SQL 注入的类型
根据攻击者与应用的交互方式和收到的反馈不同,SQLi 有几种形式。您可能会遇到 3 种主要类型:
带内(In-band)SQLi
这是最直接的类型。攻击者发送恶意 SQL 查询,并通过应用直接拿到结果。速度快,而且常常很有效。
推理型 SQLi(又称盲注,Blind SQLi)
这一类更隐蔽。攻击者不直接看到查询结果,而是通过观察应用行为来推断后台发生了什么。
- 基于布尔(内容)的 SQLi:攻击者通过添加恒真或恒假的条件(如 1=1 或 1=2)观察页面变化。是否正常加载?是否报错?是否行为异常?
- 基于时间的 SQLi:在查询中加入延时(例如
WAITFOR DELAY '00:00:05'),通过响应时间来推断条件真假。
带外(Out-of-band)SQLi(也就是“进阶玩法”)
这种较少见,但值得了解。带外 SQLi 不依赖应用的即时响应。攻击者改用 DNS 或 HTTP 等其他通道来提取数据。通常用于无法直接获得反馈、但数据库服务器可访问互联网的场景(而在 90% 的情况下,它本不该能访问)。
常见 SQL 注入技巧
我们已经了解了 3 种 SQL 注入类型。那么,攻击者在实践中如何下手?
OR 1=1 攻击
这是经典案例。想象一个需要输入用户名和密码的登录表单。攻击者可能会输入类似:
' OR 1=1 技术支持
最终 SQL 查询可能变成:
SELECT * FROM users WHERE username = '' OR 1=1 技术支持
由于 1=1 永远为真,数据库会返回所有用户记录,而 -- 会将后续查询内容注释掉。如果没有限制,攻击者甚至可能在不知道有效用户名的情况下就登录成功。

来源:vmware
注释注入
如上所示,-- 或 /* */ 用于注释掉 SQL 语句的部分内容。攻击者借此移除可能破坏其注入载荷的附加子句。比如,当不清楚原始查询的完整结构时,就可以直接“截断”,让其再次在语法上有效。
批量 SQL 语句
有些数据库允许在一次请求中运行多个 SQL 语句,以分号分隔。若应用未加限制,黑客可借此进行各类破坏,如修改数据,甚至删除表。
'; DROP TABLE users; 技术支持
基于 UNION 的攻击
通过注入 UNION SELECT 语句,攻击者可以将恶意查询与合法查询合并,从其他表中取回结果,如敏感的用户数据、密码或信用卡信息。本质上是借用现有查询来获取“额外数据”。
盲注
前面提到过,即便应用不显示错误或返回查询结果,攻击者仍可通过观察行为一点点提取数据。虽然更慢更繁琐,但行之有效。常配合工具自动化执行,可尝试上百条查询与基于时间的响应。
存储型 SQL 注入
恶意 SQL 被保存到数据库(如用户资料或评论)中,当有人查看这些数据时再被执行。
真实世界中的 SQL 注入攻击
SQL 注入听起来像是小众黑客技巧,但多年来造成了非常真实的破坏。所谓破坏,包括数百万用户记录被泄露、巨额罚款,以及让市场团队头疼的新闻头条。
Guess.com(2002)
这是一个早期且引人重视的案例。一位安全研究人员利用 SQL 注入漏洞访问了 20 多万条客户记录,包括信用卡详情。好消息是,这是由道德黑客发现并上报的。
Heartland Payment Systems(2009)
一次影响支付处理商的重大泄露,超过 1.3 亿张信用卡号被盗。攻击者通过 SQL 注入取得立足点,随后不断升级。该事件常被称为史上最大的数据泄露之一。
Yahoo! Voices(2012)
攻击者利用基于 UNION 的 SQL 注入漏洞,曝光了 45 万个用户名和明文密码。是的,您没看错,未加密的原始凭据以明文存放。此事件尤其尴尬,因为 Yahoo! 作为大型科技公司,将密码明文存储在 2012 年也是严重的“禁忌”。
TalkTalk(2015)
英国知名电信提供商 TalkTalk 遭遇一次相当基础的 SQL 注入攻击。约 15.7 万条客户记录被泄露,公司被罚款 40 万英镑。值得注意的是,其中一名攻击者仅 17 岁。
Gab(2021)
黑客维权人士利用 SQL 注入外传了 70GB 数据,包括私密帖文和哈希密码。此次泄露带有政治色彩,也引发了对 Gab 整体安全状况的进一步审视。
如何防止 SQL 注入
看过这些真实案例有点心惊后,来谈谈解决方案。好消息是,防止 SQL 注入并不复杂。大多数情况下,就是不要信任用户输入,并遵循最佳实践。您可以这样做:
使用参数化查询
这是首要规则。切勿通过字符串拼接构建 SQL 查询。应使用占位符,并将用户输入作为参数传递。大多数框架与库都已大大简化了这一做法。
例如在 Node.js 的 pg(PostgreSQL)中:
client.query('SELECT * FROM users WHERE id = $1', [userId]);技术支持
这等于是在对数据库说:“这是查询结构,这是数据,请不要把它们混在一起。”
合理使用存储过程
存储过程可以帮上忙,但前提是不要使用动态 SQL。其思想是将 SQL 逻辑放在数据库中,应用只调用这些安全、预定义的逻辑块。
如果您想学习创建、更新和执行函数与存储过程,欢迎查看我们的 Writing Functions and Stored Procedures in SQL Server 课程。
校验并清理输入
如果应用期望一个数字,就确保它真的是数字。不要盲目接受用户给的一切。使用类型检查、长度限制以及白名单(例如只允许已知的合法值)。
转义字符(如引号)也有帮助,但不能替代参数化查询。
使用 Web 应用防火墙(WAF)
WAF 可作为第一道防线,尤其对已知攻击模式有效。它能在恶意流量触达应用之前就进行拦截。虽非万无一失,但很实用,有点像 SQL 的垃圾邮件过滤器。
最小权限原则
您的 Web 应用不应以管理员权限连接数据库。限制每个用户或服务的可执行操作。例如,如果应用只需要读数据,就不要授予删除表的权限。权限越小,注入造成的破坏越有限。
SQL 注入的测试与检测
即使您认为代码很安全,也值得像攻击者那样测试。SQL 注入很容易在大型代码库或遗留系统中漏网。有不少工具与技巧能大幅简化检测流程,而且挺有“可玩性”。
手动测试
有时发现漏洞最快的方法就是“戳一戳”。试着在表单字段、URL 或任何输入位置输入 ' OR 1=1 -- 或 '; DROP TABLE users; --,看看应用如何反应。如果出现奇怪错误、意外数据或莫名其妙的成功信息,可能就发现了可疑点。
专业提示:务必在开发或预发布环境中测试。
自动化扫描器
有很多工具可以替您“动手”。一些不错的选择:
- sqlmap:开源利器,可自动化检测与利用(在道德测试场景中)。
- Burp Suite:通用的 Web 应用安全工具,带有 SQLi 检测扩展。
- OWASP ZAP:免费且适合初学者,用于发现各类 Web 漏洞。
这些工具会模拟攻击、标记潜在注入点,有时还能给出修复建议。
日志分析
另一个有效方法:监控数据库日志。反复失败的查询、奇怪的语法模式,或大量包含 '、--、或 UNION SELECT 的请求激增,都是红色警报。
结论
SQL 注入短期内不会消失,它属于“常青”威胁:简单、强大、若不谨慎就可能造成严重破坏。但 SQLi 完全可以预防。通过使用参数化查询、校验输入、落实最小权限并定期测试,您就能保护应用与用户免受 SQL 注入攻击的毁灭性影响。
请记住,没有人奢求完美,但只要稍加主动防护,您就能保护好数据库,把这项风险从清单上勾掉。如果您认真对待 SQL,并希望向潜在雇主展示实力,欢迎查看我们的 SQL Associate Certification!它将证明您有能力使用 SQL 从数据库中提取合适数据,并用其回答常见的数据问题。
SQL 注入(简称 SQLi)是黑客手册里最古老的招数之一,但至今仍然极其常见且危险。简单说,它就是诱使数据库泄露本不该公开的信息。
本文将带您了解 SQL 注入究竟是什么、攻击者如何利用它、一些造成严重损失的真实案例,以及更重要的——如何防止它发生。无论您是开发者还是对互联网漏洞机制感兴趣,读完后都能对 SQLi 有扎实的认识(而且不会读到一半睡着,我保证)。
什么是 SQL 注入?
SQL 注入是一类攻击:当有人设法篡改您的应用发送到数据库的 SQL 查询时就会发生。通常,这些查询用于获取用户资料或更新商品信息。但通过 SQLi,攻击者可以将恶意的 SQL 代码注入输入字段(如搜索框或登录表单),然后数据库就会按他们的意愿行事。
为什么会奏效?
因为在某个环节,应用过度信任了用户输入,把它当作无害文本,而不是潜在可执行代码。就像让人填一张表,然后把他们写的内容直接粘贴进命令行一样。
为什么危险?
SQL 注入的危险在于,它可被用来查看或窃取私人数据(如用户名、密码或信用卡信息)、绕过登录界面、删除或修改数据,最糟情况下甚至完全控制数据库服务器。
总之,SQLi 很糟糕,而且也不是最近才出现的安全问题,但您会惊讶有多少应用至今仍未妥善防护。
SQL 注入的类型
根据攻击者与应用的交互方式和收到的反馈不同,SQLi 有几种形式。您可能会遇到 3 种主要类型:
带内(In-band)SQLi
这是最直接的类型。攻击者发送恶意 SQL 查询,并通过应用直接拿到结果。速度快,而且常常很有效。
基于错误的 SQLi(Error-based):这种技巧依赖数据库返回的错误信息。错误可暴露大量有用信息,如表名或查询结构,从而让攻击者更容易规划下一步。
基于 UNION 的 SQLi:攻击者利用
UNION运算符合并其自定义查询与您的应用查询。这是把额外数据“拼接”进响应的一种巧妙手段。推理型 SQLi(又称盲注,Blind SQLi)
这一类更隐蔽。攻击者不直接看到查询结果,而是通过观察应用行为来推断后台发生了什么。
WAITFOR DELAY '00:00:05'),通过响应时间来推断条件真假。带外(Out-of-band)SQLi(也就是“进阶玩法”)
这种较少见,但值得了解。带外 SQLi 不依赖应用的即时响应。攻击者改用 DNS 或 HTTP 等其他通道来提取数据。通常用于无法直接获得反馈、但数据库服务器可访问互联网的场景(而在 90% 的情况下,它本不该能访问)。
常见 SQL 注入技巧
我们已经了解了 3 种 SQL 注入类型。那么,攻击者在实践中如何下手?
OR 1=1 攻击
这是经典案例。想象一个需要输入用户名和密码的登录表单。攻击者可能会输入类似:
最终 SQL 查询可能变成:
由于
1=1永远为真,数据库会返回所有用户记录,而--会将后续查询内容注释掉。如果没有限制,攻击者甚至可能在不知道有效用户名的情况下就登录成功。来源:vmware
注释注入
如上所示,
--或/* */用于注释掉 SQL 语句的部分内容。攻击者借此移除可能破坏其注入载荷的附加子句。比如,当不清楚原始查询的完整结构时,就可以直接“截断”,让其再次在语法上有效。批量 SQL 语句
有些数据库允许在一次请求中运行多个 SQL 语句,以分号分隔。若应用未加限制,黑客可借此进行各类破坏,如修改数据,甚至删除表。
基于 UNION 的攻击
通过注入
UNION SELECT语句,攻击者可以将恶意查询与合法查询合并,从其他表中取回结果,如敏感的用户数据、密码或信用卡信息。本质上是借用现有查询来获取“额外数据”。盲注
前面提到过,即便应用不显示错误或返回查询结果,攻击者仍可通过观察行为一点点提取数据。虽然更慢更繁琐,但行之有效。常配合工具自动化执行,可尝试上百条查询与基于时间的响应。
存储型 SQL 注入
恶意 SQL 被保存到数据库(如用户资料或评论)中,当有人查看这些数据时再被执行。
真实世界中的 SQL 注入攻击
SQL 注入听起来像是小众黑客技巧,但多年来造成了非常真实的破坏。所谓破坏,包括数百万用户记录被泄露、巨额罚款,以及让市场团队头疼的新闻头条。
Guess.com(2002)
这是一个早期且引人重视的案例。一位安全研究人员利用 SQL 注入漏洞访问了 20 多万条客户记录,包括信用卡详情。好消息是,这是由道德黑客发现并上报的。
Heartland Payment Systems(2009)
一次影响支付处理商的重大泄露,超过 1.3 亿张信用卡号被盗。攻击者通过 SQL 注入取得立足点,随后不断升级。该事件常被称为史上最大的数据泄露之一。
Yahoo! Voices(2012)
攻击者利用基于 UNION 的 SQL 注入漏洞,曝光了 45 万个用户名和明文密码。是的,您没看错,未加密的原始凭据以明文存放。此事件尤其尴尬,因为 Yahoo! 作为大型科技公司,将密码明文存储在 2012 年也是严重的“禁忌”。
TalkTalk(2015)
英国知名电信提供商 TalkTalk 遭遇一次相当基础的 SQL 注入攻击。约 15.7 万条客户记录被泄露,公司被罚款 40 万英镑。值得注意的是,其中一名攻击者仅 17 岁。
Gab(2021)
黑客维权人士利用 SQL 注入外传了 70GB 数据,包括私密帖文和哈希密码。此次泄露带有政治色彩,也引发了对 Gab 整体安全状况的进一步审视。
如何防止 SQL 注入
看过这些真实案例有点心惊后,来谈谈解决方案。好消息是,防止 SQL 注入并不复杂。大多数情况下,就是不要信任用户输入,并遵循最佳实践。您可以这样做:
使用参数化查询
这是首要规则。切勿通过字符串拼接构建 SQL 查询。应使用占位符,并将用户输入作为参数传递。大多数框架与库都已大大简化了这一做法。
例如在 Node.js 的 pg(PostgreSQL)中:
这等于是在对数据库说:“这是查询结构,这是数据,请不要把它们混在一起。”
合理使用存储过程
存储过程可以帮上忙,但前提是不要使用动态 SQL。其思想是将 SQL 逻辑放在数据库中,应用只调用这些安全、预定义的逻辑块。
如果您想学习创建、更新和执行函数与存储过程,欢迎查看我们的 Writing Functions and Stored Procedures in SQL Server 课程。
校验并清理输入
如果应用期望一个数字,就确保它真的是数字。不要盲目接受用户给的一切。使用类型检查、长度限制以及白名单(例如只允许已知的合法值)。
转义字符(如引号)也有帮助,但不能替代参数化查询。
使用 Web 应用防火墙(WAF)
WAF 可作为第一道防线,尤其对已知攻击模式有效。它能在恶意流量触达应用之前就进行拦截。虽非万无一失,但很实用,有点像 SQL 的垃圾邮件过滤器。
最小权限原则
您的 Web 应用不应以管理员权限连接数据库。限制每个用户或服务的可执行操作。例如,如果应用只需要读数据,就不要授予删除表的权限。权限越小,注入造成的破坏越有限。
SQL 注入的测试与检测
即使您认为代码很安全,也值得像攻击者那样测试。SQL 注入很容易在大型代码库或遗留系统中漏网。有不少工具与技巧能大幅简化检测流程,而且挺有“可玩性”。
手动测试
有时发现漏洞最快的方法就是“戳一戳”。试着在表单字段、URL 或任何输入位置输入
' OR 1=1 -- 或 '; DROP TABLE users; --,看看应用如何反应。如果出现奇怪错误、意外数据或莫名其妙的成功信息,可能就发现了可疑点。专业提示:务必在开发或预发布环境中测试。
自动化扫描器
有很多工具可以替您“动手”。一些不错的选择:
这些工具会模拟攻击、标记潜在注入点,有时还能给出修复建议。
日志分析
另一个有效方法:监控数据库日志。反复失败的查询、奇怪的语法模式,或大量包含
'、--、或UNION SELECT的请求激增,都是红色警报。结论
SQL 注入短期内不会消失,它属于“常青”威胁:简单、强大、若不谨慎就可能造成严重破坏。但 SQLi 完全可以预防。通过使用参数化查询、校验输入、落实最小权限并定期测试,您就能保护应用与用户免受 SQL 注入攻击的毁灭性影响。
请记住,没有人奢求完美,但只要稍加主动防护,您就能保护好数据库,把这项风险从清单上勾掉。如果您认真对待 SQL,并希望向潜在雇主展示实力,欢迎查看我们的 SQL Associate Certification!它将证明您有能力使用 SQL 从数据库中提取合适数据,并用其回答常见的数据问题。