SQL注入漏洞全面解析与防御指南
1. SQL注入概述
SQL注入是Web安全中最常见且危险的漏洞之一,位列十大Web安全漏洞之中。其本质是应用程序对用户输入数据未进行充分验证和过滤,导致攻击者能够构造恶意SQL语句并执行。
1.1 SQL注入产生条件
- 参数用户可控:攻击者能够控制输入参数
- 参数动态拼接SQL语句:应用程序直接将用户输入拼接到SQL查询中
- 参数过滤不严:缺乏有效的输入验证和过滤机制
2. SQL注入分类
2.1 按注入效果分类
2.1.1 UNION联合注入
-
适用条件:
- 参数所在SQL语句为查询语句
- 页面存在回显
- 示例:
select * from users where id="$id"
-
利用方法:
- 使用
order by判断列数 - 使用
select 1,2,3...确定回显位 - 构造
union select语句获取数据库信息 - 使用
concat()或group_concat()合并多行结果
- 使用
2.1.2 布尔盲注
- 适用条件:页面无回显信息,但不同输入会导致不同页面响应
- 利用方法:
- 构造条件判断语句:
id=0' or length(database())>4 --+ - 逐字符判断:
id=0' or substring(database(),1,1)='s'--+ - 使用ASCII码判断:
id=0' or ord(substring(database(),1,1))=65 --+
- 构造条件判断语句:
2.1.3 时间盲注
- 适用条件:不同输入页面响应相同,但可通过响应时间判断
- 利用方法:
- 结合
if()和sleep()函数:if(1=1,sleep(1),1) - 通过页面响应时间判断条件真假
- 结合
2.1.4 报错注入
- 适用条件:SQL语句执行错误后页面显示错误信息
- 常见报错方法:
- XPATH报错(MySQL 5.1.5+):
extractvalue():id=0'or (select extractvalue(1,concat('!',database()))) --+updatexml()
- floor型报错:
- 结合
rand()、group by使用 - 示例:
0' or (select count(*) from users group by concat(database(),floor(rand(0)*2)))--+
- 结合
- 几何函数报错(MySQL 5.5.47-5.7.17):
geometrycollection(),multipoint(),polygon()等- 示例:
id = 1 and GeometryCollection((select from (select from(select database())a)b))
- 整数溢出报错:
- 使用
~0表示最大整数值:id=0'or (select(~0+!(select * from (select database())a))) --+ exp函数:(select exp(~(select * from (select database())a))) --+
- 使用
- XPATH报错(MySQL 5.1.5+):
2.1.5 堆叠注入
- 原理:利用SQL语句中
;分隔多条语句的特性 - 风险:可执行任意合法SQL语句,包括删除数据等危险操作
- 限制:多数服务器限制一次只能执行一条SQL语句
2.1.6 二次注入
- 原理:
- 用户上传参数时被转义(如
test'变为test\') - 从数据库取出数据时未再次转义
- 导致原始注入语句被还原执行
- 用户上传参数时被转义(如
- 示例:
- 输入:
test' union select 1,2,version() --+ - 查询时变为:
select * from user where username='test' union select 1,2,version() --+'
- 输入:
2.2 按提交方式分类
2.2.1 GET注入
- 参数出现在URL中
- 受URL长度限制
2.2.2 POST注入
- 参数通过POST请求体提交
- 多见于表单
2.2.3 HTTP头注入
- 注入点位于HTTP头部字段
- 常见注入点:
- Cookie
- HTTP_CLIENT_IP
- HTTP_X_FORWARDED_FOR
- User-Agent
- Referer
3. 文件读写操作
3.1 条件
- 了解目标主机路径
- 有相应读写权限
- 可使用
outfile、load_file()等函数
3.2 风险
- 写入webshell
- 通过工具(如中国菜刀、webacoo)连接控制服务器
4. SQL注入绕过技术
4.1 大小写绕过
- 示例:
Union代替union - 现代WAF基本已防御
4.2 双写绕过
- 示例:
uniunionon过滤后变为union - 主要用于过滤替换型WAF
4.3 编码绕过
- URL编码
- Unicode编码
- Hex编码等
4.4 注释绕过
- 示例:
id=1 /*!union*/ /*!select*/ - 或:
union /*kuyed*/ select /*iuysv*/ 1
4.5 宽字节绕过
- 条件:客户端与服务端编码不一致(如PHP utf8,MySQL gbk)
- 方法:在
/前加%df
4.6 Cookie绕过
- 利用
$_REQUEST获取参数顺序(GET > POST > COOKIE) - 当程序只检测GET/POST时,通过COOKIE传参
4.7 非常用函数
- 使用WAF不检测的冷门函数
5. SQL注入防御措施
5.1 基本原则
- 永远不信任用户输入:包括数据库返回的数据
- 拒绝而非修复:直接拒绝可疑请求而非尝试修复数据
5.2 参数化查询(预处理语句)
- 使用PDO的
bind_param()绑定参数 - 避免SQL语句动态拼接
- 示例:
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id'); $stmt->bindParam(':id', $id, PDO::PARAM_INT); $stmt->execute();
5.3 严谨编码实践
- 生产环境移除调试信息(如
mysql_error) - 验证数据最终存储需求(如字段长度限制)
5.4 最小权限原则
- 区分读写用户权限
- 业务用户仅拥有必要的最小权限
6. XSS注入(跨站脚本攻击)
6.1 分类
- 反射型:非持久化,通过URL等即时触发
- 存储型:持久化到数据库,所有访问者受影响
- DOM型:完全在客户端执行
- 基于页面型
6.2 常见触发方式
6.2.1 事件触发
onclick:点击元素时onerror:资源加载失败时onmouseover:鼠标悬停时onload:元素加载完成时
6.2.2 常用标签
<script>alert("xss");</script>- ``
<a href=javascript:alert('xss')>test</a><iframe onload=alert("xss");></iframe><svg onload=alert(1)>
6.3 XSS绕过技术
6.3.1 编码绕过
- Unicode编码
- Base64编码
- URL编码
6.3.2 特殊构造
- 使用
data:协议:data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4= - 拼接绕过:``
- 优先级绕过:
<title>>
6.4 XSS防御措施
6.4.1 输入过滤
- 使用
htmlspecialchars()转义HTML特殊字符 - 白名单验证输入内容
6.4.2 纯前端渲染
- 静态HTML不包含业务数据
- 明确设置内容类型(
.innerText、.setAttribute等)
6.4.3 HttpOnly Cookie
- 禁止JavaScript读取敏感Cookie
7. 命令注入漏洞
7.1 产生条件
- 执行系统命令的函数参数用户可控
- 后端过滤不严格
7.2 危险函数(PHP)
system()exec()shell_exec()passthru()popen()proc_popen()
7.3 命令拼接符
7.3.1 Windows
$, `
\[`, `|`, `||` #### 7.3.2 Linux - `&`:后台运行 - `;`:命令结束符 - `|`:管道 - `&&`:前命令成功则执行后命令 - `||`:前命令失败则执行后命令 ### 7.4 绕过技术 #### 7.4.1 通配符 - `?`:匹配单个字符 - `*`:匹配任意字符 - `[]`:字符集匹配 - 示例:`cat /*tc/pa??wd` #### 7.4.2 未定义变量 - Linux中未定义变量为null - 示例:`cat$a /etc$a/passwd$a` #### 7.4.3 反引号与$() - 将命令结果保存到变量 - 示例:`echo $(pwd)` #### 7.4.4 关键字替换 - `cat` → `more`、`vi`、`head`等 #### 7.4.5 分段写入执行 - 将代码分段写入文件再执行 - 适用于长度受限情况 ### 7.5 命令注入防御 #### 7.5.1 输入验证 - 严格校验输入格式(如IP地址、URL等) #### 7.5.2 白名单限制 - 限制参数允许的内容 #### 7.5.3 最小权限 - Web应用程序使用最低必要权限 ## 8. 代码注入漏洞(PHP) ### 8.1 文件包含漏洞 #### 8.1.1 危险函数 - `include()` - `include_once()` - `require()` - `require_once()` #### 8.1.2 利用方式 - 包含恶意构造的文件 - 远程文件包含(需`allow_url_include`开启) #### 8.1.3 常见协议 - `http(s)://`:远程文件包含 - `file://`:本地文件访问 - `zip://`:访问压缩包内文件 - `data://`:直接包含数据流 - `php://`:特殊PHP流 #### 8.1.4 绕过技术 - 路径遍历:`../../../etc/passwd` - 空字节截断(PHP版本限制) - 超长路径截断 ### 8.2 代码执行函数 #### 8.2.1 直接执行 - `eval()`:执行字符串作为PHP代码 - `assert()`:与`eval`类似 #### 8.2.2 正则执行 - `preg_replace()`的`e`修饰符(已弃用) #### 8.2.3 回调函数 - `call_user_func()` - `array_map()` - `usort()`等 #### 8.2.4 动态函数 - `$func = "system"; $func("whoami");` - ` \]
`可变变量
8.3 代码注入防御
8.3.1 避免危险函数
- 尽量不使用
eval()、assert()等
8.3.2 严格输入过滤
- 过滤特殊字符(
/,.,..等) - 限制文件包含路径
8.3.3 权限控制
- 重要文件加密存储
- 使用非常见路径名称
9. 总结
9.1 核心防御原则
- 不信任任何用户输入
- 最小权限原则
- 防御性编程
- 持续更新与补丁
9.2 开发者自查清单
- 是否使用预处理语句?
- 是否过滤所有用户输入?
- 是否关闭错误回显?
- 是否使用最低必要权限?
- 是否定期更新依赖库?
9.3 渗透测试要点
- 识别所有用户输入点
- 尝试各种注入技术
- 验证过滤与转义机制
- 检查错误处理方式
- 评估漏洞潜在影响
通过全面理解这些注入漏洞的原理、利用方式和防御措施,开发人员可以构建更安全的Web应用程序,安全人员也能更有效地发现和修复这些漏洞。