sqlmap是最该先试的sql注入检测工具,但需先手动验证参数可测性(如?id=1'是否触发数据库错误)、明确请求结构(get/post/json)、合理设置--level、--risk、--threads及绕过waf参数,再交由其自动化判断注入点。

sqlmap 是你最该先试的工具,它能快速验证接口是否真有 SQL 注入漏洞,而不是靠猜或手动拼接一堆单引号。但直接丢一个生产 URL 进去,大概率会漏判、误报,甚至触发 WAF 或日志告警——这不是工具不行,是你没告诉它该怎么“问问题”。
确认目标 URL 和参数是否可测
SQL 注入只发生在「用户输入参与拼接 SQL 语句」的地方,比如 ?id=1、?username=admin、POST /login 的 JSON body 里字段。别测首页、静态资源路径或没参数的接口。
- 先用浏览器或
curl手动发一次正常请求,确认返回是预期数据(比如查到用户信息),不是 404/500/空响应 - 在参数值末尾加单引号,比如
?id=1',看是否返回数据库错误(如MySQL syntax error、ORA-00936)——有错不等于可注入,但没错大概率要换思路(比如盲注) - 如果接口走 POST 且是 JSON,
sqlmap默认不解析 body,得加--data参数显式传原始 payload,例如:sqlmap -u "http://localhost:8000/api/user" --data='{"id":"1"}' -r request.txt
用 sqlmap 做最小化探测
别一上来就跑 --dbs 或 --dump,先让工具判断「这个参数到底能不能注入」。默认行为足够敏感,但你要关掉干扰项:
- 加
--level 2 --risk 1:跳过高风险 payloads(如堆叠查询),避免被拦截或写坏测试库 - 加
--threads 3:并发别太高,防止把本地开发服务打挂 - 如果目标用了 Cloudflare、ModSecurity 等 WAF,加
--random-agent和--delay 1降低被封概率 - 遇到重定向或登录态,用
-c指定配置文件或--cookie传 session,否则sqlmap看不到后端真实响应
识别盲注时的关键信号
很多现代接口即使存在注入,也不报错、不回显数据——这就是盲注。这时候 sqlmap 依赖页面内容变化或响应时间来判断,但容易误判:
- 如果页面返回 JSON,且只有
{"code":0,"data":[]}这类固定结构,sqlmap可能无法区分真假响应,需加--string "code\":0"指定成功标识 - 基于时间的检测(
--technique T)会发SLEEP(5)类请求,务必确认数据库支持该函数(MySQL 支持SLEEP(),PostgreSQL 要用pg_sleep()),否则全判为“不可注入” - 若开发环境数据库是 SQLite,
sqlmap默认不启用 SQLite 检测,得加--dbms sqlite显式指定,否则跳过
绕过简单过滤的常见陷阱
你可能在代码里写了类似 str_replace("'", "", $id),以为就安全了——sqlmap 仍可能绕过:
- 它会自动尝试双写绕过(
''→'''')、编码绕过(%27)、大小写混合(UnIoN)、注释符切割(UNION/*abc*/SELECT) - 如果过滤只针对 GET 参数,但接口同时接受 POST 或 Header(如
X-User-ID),sqlmap可通过-p "X-User-ID"指定测试 Header,这点常被忽略 - 某些 ORM(如 Django 的
filter(id__exact=...))本身防注入,但若你混用了extra()或原生 SQL,sqlmap仍能打穿——别假设“用了框架就没事”
sqlmap 的“vulnerable”结果,而是理解它为什么说“not vulnerable”:是真没洞,还是你没给对上下文?比如漏了 Cookie、没处理 CSRF Token、响应体结构太单一。这些细节不调通,工具再强也白搭。











