文章目录
-
- 一、注入到底是什么病
- 二、入门前先搭对练习场
- 三、手工注入:你得先会"证明它存在"
-
- [1. 找候选点](#1. 找候选点)
- [2. 制造"语法异常"](#2. 制造“语法异常”)
- [3. 判断是数字型还是字符型](#3. 判断是数字型还是字符型)
- [4. 布尔盲注:用真假问问题](#4. 布尔盲注:用真假问问题)
- [5. 时间盲注:页面完全一样时](#5. 时间盲注:页面完全一样时)
- [6. 报错注入:数据库肯说话时](#6. 报错注入:数据库肯说话时)
- [7. Union 注入:能拼结果集时](#7. Union 注入:能拼结果集时)
- [8. 别只会 SELECT](#8. 别只会 SELECT)
- 四、手工阶段的"熟练"标准
- 五、sqlmap:自动化该怎么用才像老手
-
- [1. 使用前的纪律](#1. 使用前的纪律)
- [2. 最小而有效的用法思路](#2. 最小而有效的用法思路)
- [3. 和代理配合](#3. 和代理配合)
- [4. 速度与隐蔽](#4. 速度与隐蔽)
- [5. sqlmap 不是全能神](#5. sqlmap 不是全能神)
- 六、进阶:你会在真实项目里撞上的硬骨头
- 七、防御:怎样才算"修好了"
-
- [1. 参数化是主药](#1. 参数化是主药)
- [2. 白名单处理结构型输入](#2. 白名单处理结构型输入)
- [3. 最小权限](#3. 最小权限)
- [4. WAF 是辅药](#4. WAF 是辅药)
- [5. 安全测试要进 CI / 发布清单](#5. 安全测试要进 CI / 发布清单)
- [6. 日志与监控](#6. 日志与监控)
- 八、给开发的"代码评审口头禅"
- 九、给授权测试同学的报告写法
- 十、一条建议的学习路线(真正能精通的那种)
- 十一、收尾
先说一句扫兴的:如果你是想拿这篇去扫公网捡鱼,停一下。SQL 注入相关技术只适合你拥有授权的系统、自己的靶场、合同范围内的渗透测试。未授权对他人系统做注入,在绝大多数地区都是违法的------这篇按《网络安全实战》的写法,默认读者是开发、测试、蓝队和授权打手。
再说一句更扫兴的:SQL 注入明明"过时"了十几年,怎么还在打穿系统?因为业务总有"临时拼一下"的报表、导出、高级搜索、老项目、存储过程、以及那个"框架能防,所以我这里例外"的人。
我写这篇,不想写成字典式的 payload 大全。更想带你走一条真实学习路径:先看懂注入为什么成立 → 手工把洞证出来 → 再用 sqlmap 加速与减少遗漏 → 最后知道怎么改代码、怎么做回归,让洞真正消失。
"精通"不是背两百条绕过,是看见代码就知道危不危险,看见请求就知道怎么验证,看见修复就知道可不可信。
一、注入到底是什么病
把 SQL 想成你跟数据库说的一句话。正常情况是:
请给我
user_id = 当前登录用户的订单。
一旦应用这么写(示意):
text
"SELECT * FROM orders WHERE id = " + userInput
用户输入就不再只是"数据",而可能改写这句话的语法。比如输入里带上注释、条件、联合查询,语义就变了。
所以注入的本质就一句:
不可信输入,进入了 SQL 语句的结构,而不是仅仅进入了值的位置。
预编译 / 参数化绑定之所以是解药,是因为它强制"结构"和"值"分离:值再怎么花,也成不了新的 SQL 语法。
二、入门前先搭对练习场
别一上来打真实客户系统练手。建议:
- DVWA、sqli-labs、自建的故意脆弱 Demo;
- 本地 MySQL/PostgreSQL/MSSQL 任一即可;
- 浏览器 + 代理(Burp / 同类)看请求;
- 授权测试时再换成客户环境,并明确范围。
有代理很重要。很多"注入点"藏在 JSON 字段、Cookie、二次提交、HTTP 头里,页面上看不见。
另外请记住数据库方言差异:MySQL、PostgreSQL、MSSQL、Oracle 的报错信息、字符串拼接、布尔盲注函数都不一样。精通的人先认库,再选手法。
三、手工注入:你得先会"证明它存在"
工具会撒谎,也会漏报。手工的价值是建立直觉。
1. 找候选点
优先怀疑:
- 登录框(有时是注入,有时只是弱口令,别混);
- 列表筛选、排序字段、
id=、order=、search=; - 导出 Excel / 报表;
- 旧接口、移动端 API、管理端"高级查询"。
看请求里哪些参数最终可能进了 SQL。黑盒阶段靠猜与试;白盒阶段直接搜字符串拼接。
2. 制造"语法异常"
最经典的试探仍是加单引号、双引号、括号,让语句变得不完整。若页面从"正常列表"变成"数据库报错"或"异常 500",你就找到了一根线头。
但现在很多系统关了详细报错,只给你一句"系统繁忙"。于是要会看:
- 响应长度变了吗?
- 响应时间变了吗?
- 结果集条数变了吗?
这就是盲注思维的起点:没有报错,不代表没有注入。
3. 判断是数字型还是字符型
粗线条理解:
- 数字型:原语句可能是
WHERE id = 7,你输入的是数字位置; - 字符型:原语句可能是
WHERE name = 'admin',你要考虑引号闭合。
判断准了,后面的闭合方式才不瞎碰。
4. 布尔盲注:用真假问问题
思路是构造永远为真 / 永远为假的条件,观察页面差异。例如(概念上)让条件变成"原条件 AND 1=1"与"AND 1=2"。若两种输入对应两种页面,你就拥有了一位信息的信道------然后可以一位一位问出库名、表名。慢,但稳。
手工做布尔盲注很磨人,所以这一步重在确认洞在、理解回显通道;大规模抠数据留给自动化。
5. 时间盲注:页面完全一样时
若真假页面毫无差别,可借助数据库睡眠类函数(各库名字不同)让"条件为真时更慢"。用时间当信号。
注意:网络抖动会骗人,要多次测,别一次超时就下结论。
6. 报错注入:数据库肯说话时
有些环境会把 SQL 异常直接吐到页面或接口 JSON 里。那是手工的天堂,也是开发的地狱。利用报错把信息"挤"进异常文本------具体函数因库而异,学的时候按你靶场的库去查文档,别死记一套通杀。
7. Union 注入:能拼结果集时
当结果会直接显示在页面上,联合查询可以把其它表的数据拼进结果集。关键步骤通常是:判断列数、找到回显列、再查询元数据(表名列名)与业务表。
列数可用 ORDER BY 递增到报错来估(老手法),或用 UNION 试。现代防护与模板渲染可能让回显很难看,但逻辑仍是那套。
8. 别只会 SELECT
写权限若很宽,注入的危害会从"拖库"变成"改数据、写文件、提权"------取决于数据库账号权限与组件。所以修洞时不要只说"防注入",还要问:数据库账号是不是权限过大?
四、手工阶段的"熟练"标准
我觉得够格叫"入门到手熟",至少能做到:
- 独立确认一个点是否可注入(含盲注);
- 说出大致是哪类(布尔 / 时间 / 回显 / 报错);
- 判断大致后端库类型;
- 评估危害:只读?能否碰其它库?跑的是什么账号;
- 写得出清晰复现步骤给开发(参数、payload 思路、期望现象),而不是丢一句"有 SQL 注入"。
至于把整库导出来------在授权测试里有时需要证明影响,更多时候点到为止 + 出报告更专业。别把客户库当练习册狂拖。
五、sqlmap:自动化该怎么用才像老手
sqlmap 是授权测试里几乎人人会摸的工具。它强在:技巧覆盖面广、指纹识别、取数据流程化。
它也蠢在:参数乱扫、目标乱填时,你会对生产打出一堆睡眠请求,然后业务说数据库怎么卡死了。
1. 使用前的纪律
- 确认书面授权与范围;
- 先 staging / 测试环境;
- 生产若必须测,控制线程、去掉极具破坏性的选项、避开高峰;
- 能手工确认的点,再交给 sqlmap 深挖,减少误伤。
2. 最小而有效的用法思路
把请求交给它:URL、POST 体、Cookie、或从代理导出的 request 文件。
指定参数,而不是一上来全自动乱撞所有参数。
常见能力(概念层面,具体参数以你安装版 sqlmap -h 为准):
- 探测技术类型(布尔、时间、UNION......);
- 识别数据库类型与版本;
- 列举库表列;
- 按条件取数;
- 风险与级别开关(越高越激进)。
老手一般这样走:
text
先低攻击性探测 → 确认可注入
→ 查当前库/当前用户权限
→ 证明可读取敏感表的少量样例
→ 收工写报告
而不是默认"全库 dump"。
3. 和代理配合
复杂请求(多头部、JSON、CSRF token)用"原始请求文件"丢给 sqlmap,比在命令行里一点点拼更少出错。Token 会过期的,要注意刷新。
4. 速度与隐蔽
线程加得很猛,等于给自己报信:DBA 先发现异常,安全部还没出报告。
授权测试里,稳比快重要;需要时再逐步提高。某些环境还有 WAF,工具被拦不等于没洞,可能要回到手工换通道------但绕过 WAF 的细节不应写成"教你偷摸打生产"的菜谱;在授权范围内、以验证风险为目的去做,并优先推动修复与规则调优。
5. sqlmap 不是全能神
它可能漏:
- 很深的二阶注入(先存后触发);
- 强定制 ORM 下奇特的拼接位置;
- 必须特定业务步骤才拼出的 SQL;
- 权限极低只能看极少视图的场景。
所以我才说:手工负责"发现与理解",工具负责"加速与减少机械劳动"。两者缺一,都会在某天丢人。
六、进阶:你会在真实项目里撞上的硬骨头
二阶注入
输入时看起来没事,入库后在另一处拼接查询时爆炸。测试要覆盖"写进去再读出来"的路径,比如改昵称后管理端搜索昵称。
订单字段 / 列名注入
ORDER BY 后面跟列名,参数化不好直接套。常见修法是白名单映射:前端传 created / price,后端翻译成真正列名,绝不把用户字符串直接拼进 ORDER BY。
LIMIT / 翻页 / 排序组合
翻页参数也能出问题。一律校验为整数,或白名单。
存储过程与动态 SQL
数据库里用字符串拼 SQL,同样危险。权限上让应用账号不能乱动态拼。
ORM 并不自动等于安全
ORM 大多数 API 安全,但 raw query、字符串拼 fragment、某些 order(userInput) 仍会翻车。代码审计时搜 raw、execute(、字符串加号拼 SQL。
读写分离与权限
即使注入得手,若账号只有单库只读,危害可被限制。这是防御纵深,不是借口不修注入。
七、防御:怎样才算"修好了"
1. 参数化是主药
各语言都有 prepared statement / 参数绑定。原则是:
SQL 模板固定,用户输入只当绑定值。
包括 INSERT/UPDATE/DELETE,不只是 SELECT。
2. 白名单处理结构型输入
表名、列名、排序方向、运算符,这些本来就不是"值",绑参绑不了,必须用白名单。
3. 最小权限
应用连接库的账号:不要 DBA;不要随意 FILE;不要跨到无关库。出事时少哭一会儿。
4. WAF 是辅药
WAF 能挡一批脚本小子,拦不住细心构造与业务定制注入。被 WAF 挡住 ≠ 代码安全。 真正通关看代码与测试。
5. 安全测试要进 CI / 发布清单
- 代码扫描找拼接;
- 对历史注入点留回归请求包;
- 依赖与框架升级(有时驱动层也有洞)。
6. 日志与监控
短时间大量 SQL 错误、异常长查询、睡眠函数特征(若可在 DB 侧审计)、导出接口疯狂访问------这些能给蓝队线索。别指望只靠 WAF 日志。
八、给开发的"代码评审口头禅"
评审遇到数据库访问,我就问四句:
- 这句 SQL 有没有字符串拼接用户输入?
- 排序/过滤字段从哪来,白名单了吗?
- 这个库账号能干什么?
- 出错时会不会把 SQL 细节回给客户端?
四句都过得去,注入风险会少一大截。
九、给授权测试同学的报告写法
别只会贴 sqlmap 大截图。甲方开发恨这种报告。
写清楚:
- 漏洞位置(URL、参数、方法);
- 类型(如布尔盲注);
- 复现步骤(尽量最小 payload);
- 证明(当前用户、版本、或样例数据一行,注意脱敏);
- 影响(可读哪些数据、是否可写);
- 修复建议(参数化示例、权限收敛);
- 复测标准。
专业,比"拖了整库"更让人愿意请你第二次。
十、一条建议的学习路线(真正能精通的那种)
第 1 周
靶场上手工:报错、布尔、UNION,各打通一个。写下笔记:你怎么判断库类型的。
第 2 周
同一漏洞用 sqlmap 复现;对比手工与工具的差异;学会控制速度与范围。
第 3 周
读两段真实项目代码(或开源烂代码),找拼接;尝试写修复补丁与回归测试。
第 4 周
做二阶、ORDER BY、JSON 接口各一例;写一份完整测试报告模板。
之后就是积累:不同方言、不同框架、不同 WAF 环境。精通是年限与案例数,不是一篇文章的承诺------但路径可以很清楚。
十一、收尾
SQL 注入从入门到精通,中间那道坎其实不是"会不会用 sqlmap",而是:
你有没有把问题看成工程缺陷:输入边界、查询构造、账号权限、测试门禁,而不是一串神秘 payload。
手工让你诚实,工具让你高效,修复让你对得起授权你测试的人。三者齐了,才配谈实战。
今晚如果你只做一件事:在靶场里不要开 sqlmap,手工确认一个布尔盲注点,写出"真假输入各自的现象"。 做完这件事,你对注入的理解,会比先跑三天工具扎实得多。
等你手工也能稳定证洞了,再让 sqlmap 替你打工------那时候,它才是工具,而你不是它的搬运工。