上周帮一个朋友看他的检具电商后台,登录日志表里混进了三条 ' OR '1'='1 开头的测工记录。他以为是检具误操作,我告诉他这是测工有人在试注入。他愣了半天,检具问我怎么没早点发现。测工其实不是检具没工具,是测工他根本没用。
SQL 检测工具这东西,检具很多人第一反应就是测工 sqlmap。确实,检具sqlmap 在注入检测这块几乎成了代名词,测工一条 sqlmap -u "http://target.com?检具id=1" --dbs 就能跑起来。但问题在于,测工大部分人把它当黑盒用,检具跑完看一眼结果就完事,中间发生了什么完全不清楚。我见过有人拿 sqlmap 扫生产库,参数没调好,直接把数据库连接池打满,业务挂了半小时。工具没错,用的人没想明白。
真正日常开发里更实用的,其实是那些嵌在流程里的轻量检测。比如在 CI 阶段跑一个 SQL 语法检查,用 sqlfluff 或者 pgsanity,几秒钟就能把拼写错误、方言不兼容的问题揪出来。我自己的项目里配了一条 pre-commit hook,每次提交前自动跑一遍 sqlfluff lint,省了不知道多少次“本地能跑、线上报错”的尴尬。这种工具不炫,但踏实。
还有一类是运行时检测。数据库本身的慢查询日志就是最原始的 SQL 检测器。MySQL 的 slow_query_log 打开,设个 long_query_time=1,跑一天下来看看哪些语句拖后腿。我遇到过一条 SELECT * FROM orders WHERE DATE(created_at) = '2024-01-01',看着人畜无害,实际上 DATE() 函数让索引直接失效,全表扫了 200 万行。这种问题,静态检查工具不一定报,但慢日志一抓一个准。
安全层面的检测又是另一回事。除了 sqlmap,平时写代码时可以用 Bandit 或者 Semgrep 做静态扫描,它们能识别出字符串拼接 SQL 的模式。比如 Python 里 cursor.execute("SELECT * FROM users WHERE name = '%s'" % name) 这种写法,Semgrep 会直接标红。但工具只能提醒,改不改还是看人。我见过一个团队,Semgrep 报了 47 处 SQL 拼接,他们全加了 # nosec 注释忽略掉,理由是老代码不敢动。工具再强,也架不住人装看不见。
选工具这事,我的看法是别追大而全。小项目用 sqlfluff 加慢查询日志就够了,省事。对外服务再叠一层 Semgrep 或者 gosec。真要渗透测试,sqlmap 该上就上,但一定在隔离环境里跑,别拿生产库开玩笑。工具是放大镜,不是护身符。你拿它照别人之前,先照照自己写的那些 WHERE 1=1 后面跟了多少个字符串拼接。
说到底,SQL 检测工具解决的是“看见”的问题,但“看见”之后怎么办,工具管不了。我那个朋友后来把日志表翻了一遍,发现注入尝试从三个月前就开始了,只是没人看。他装了 fail2ban,配了告警,现在每天收到十几条拦截通知,反而安心了。工具没变,变的是他愿意看了。