SQL 注入总结
SQL 注入是攻击者利用 Web 应用对用户输入验证的疏忽,将恶意 SQL 命令注入后台数据库执行,进而窃取、篡改数据或控制服务器的漏洞攻击方式。
一、注入原理与条件
- 核心原理服务端未过滤用户输入的恶意数据,直接将其拼接进 SQL 语句执行,改变原语句语义,引发安全风险。
- 必要条件
- 用户能够控制输入参数(如 URL、表单、Cookie 等)。
- 程序将用户输入直接拼接进 SQL 语句,未做有效处理。
二、注入分类
1. 按注入点类型分
| 类型 | 说明 | 测试方法 |
|---|---|---|
| 数字型注入 | 参数为整数(如 ID),SQL 语句无引号包裹 | id=1 and 1=1(正常)、id=1 and 1=2(异常) |
| 字符型注入 | 参数为字符串,SQL 语句有引号包裹 | user=admin' and '1'='1(正常)、user=admin' and '1'='2(异常) |
| 搜索型注入 | 注入点为搜索框,SQL 语句含 like '%关键字%' | keyword=' and 条件 and '%'=' |
2. 按注入技术分
- 基于报错的注入:利用
extractvalue()、updatexml()等函数,使数据库报错并回显敏感信息。 - 基于布尔的盲注:根据页面返回的
True/False判断条件真假,逐字符猜解数据。 - 基于时间的盲注:利用
sleep()等延时函数,通过页面响应时间判断条件是否成立。 - 联合查询注入:使用
UNION SELECT拼接查询语句,直接获取数据库数据。 - 堆查询注入:同时执行多条 SQL 语句(如
; INSERT/UPDATE/DELETE...)。 - HTTP 头部注入:注入点为
User-Agent、Cookie、Referer等 HTTP 头字段。
三、预编译与 SQL 注入的关系
- 预编译的作用预编译(参数化查询)将 SQL 语句结构与参数分离,数据库先编译语句模板,再绑定参数执行,可消除 SQL 语句歧义,防御大部分注入。
- 预编译的局限性
- 仅能防御可参数化位置的注入,表名、列名、order by、group by等 SQL 结构位置无法参数化,仍存在注入风险。
- 分为真预编译和模拟预编译:模拟预编译仅做字符转义,存在宽字节注入风险;真预编译需关闭
PDO::ATTR_EMULATE_PREPARES,安全性更高。
- 预编译下的注入场景
- 宽字节注入:编码不一致(如 GBK)导致转义符
\被吞,单引号逃逸。 - 无参数绑定:预编译语句直接拼接用户输入,等同于未防护。
- 协议层注入:利用数据库二进制协议的长度截断漏洞(如 CVE-2024-27304),绕过预编译逻辑。
- 宽字节注入:编码不一致(如 GBK)导致转义符
四、注入过程(手工注入)
- 判断注入点:通过单引号、
and 1=1/1=2测试页面响应。 - 判断字段长度:使用
order by N确定查询结果的列数。 - 判断回显位置:使用
union select 1,2,3...找到可显示数据的列。 - 获取数据库信息:通过
database()、version()、user()等函数获取基础信息。 - 遍历数据库 / 表 / 字段:查询
information_schema系统库,获取所有库名、表名、列名。 - 获取敏感数据:查询目标表的字段值(如用户名、密码)。
- 后续利用:登录后台、写入 webshell、执行系统命令等。
五、自动化注入工具(SQLMap)
- 核心功能:自动检测注入点、识别数据库类型、获取敏感数据。
- 常用命令
- 检测注入点:
sqlmap -u "http://test.com/index.php?id=1" - 列出所有数据库:
sqlmap -u "URL" --dbs - 列出指定库的表:
sqlmap -u "URL" -D 库名 --tables - 导出指定字段数据:
sqlmap -u "URL" -D 库名 -T 表名 -C 字段1,字段2 --dump
- 检测注入点:
六、防御措施
- 使用预编译语句:强制使用参数化查询,避免字符串拼接。
- 输入过滤与验证:过滤特殊字符(单引号、分号等),严格校验参数类型和长度。
- 处理字符编码:统一使用 UTF-8 编码,避免宽字节注入;设置
character_set_client=binary。 - 最小权限原则:数据库账户仅赋予必要权限,禁止使用 root 等高权限账户。
- 关闭错误回显:生产环境禁用数据库错误信息展示,避免泄露敏感信息。
- 部署 WAF:使用 Web 应用防火墙拦截恶意 SQL 注入请求。

1万+

被折叠的 条评论
为什么被折叠?



