发现可疑SQL错误日志后应立即冻结相关接口、禁用公网访问、提取含敏感字符的请求并核查审计日志是否开启,未开启则导出活跃连接与查询,同时全面排查各层SQL拼接点及ORM原生调用风险。

发现可疑SQL错误日志后该立即做什么
看到数据库报错里出现 mysql_fetch_array()、ORA-00936 或带 UNION SELECT 的长查询,别先查代码,先冻结相关接口。真实案例中,某电商在日志里扫到 ' OR SLEEP(5) -- 这类 payload 时,已有多次慢查询触发了监控告警,但团队仍花17分钟才定位到登录页参数未过滤。
- 立刻禁用该接口的公网访问(Nginx return 503 或 WAF 规则临时拦截)
- 从应用日志里提取最近2小时所有含单引号、分号、
--、/*、UNION的请求 URL 和参数 - 检查数据库审计日志是否开启——没开就停机前先导出当前连接和活跃查询:
SHOW PROCESSLIST;、SELECT * FROM information_schema.PROCESSLIST WHERE TIME > 60;
确认注入点时别只盯PHP或Java代码
现代栈里,注入可能藏在任何拼接SQL的地方:Node.js 的 pg.query()、Python 的 cursor.execute()、甚至前端发往后端的 GraphQL 变量解析逻辑。某 SaaS 系统被攻破,根源是 TypeScript 客户端把用户输入直接塞进 fetch(`/api/users?name=${input}`),后端再用该参数拼接 SQL。
- 逐个检查所有数据库调用点,重点看是否用了
string interpolation或format()拼接,而不是prepare()/execute()分离 - 对 ORM 框架要警惕“原生 SQL”模式:Django 的
raw()、SQLAlchemy 的text()、MyBatis 的$符号(非#)都是高危信号 - 检查中间件或网关层是否做过滤——有些团队在 Nginx 里用
if ($args ~* "(union|select|sleep)") { return 403; },但正则漏掉大小写变体或 URL 编码绕过
修复上线前必须验证的三件事
修完代码不能直接上生产。某金融系统修复后,因测试环境没配审计日志,上线5分钟后又被同一种 payload 打穿——攻击者利用了修复时漏掉的另一个管理接口。
- 用原始 payload(如
admin'--、1' UNION SELECT version(),2,3--)在预发环境重放,确认返回 400 或空结果集,而非数据库错误页 - 确认数据库账号权限已收紧:
SELECT权限仅限业务表,禁止information_schema查询,删掉DROP、CREATE权限 - 检查 WAF 规则是否覆盖新 payload 变种:比如把
--换成%23(#号 URL 编码)、UNION换成unIoN,WAF 若只做关键词匹配会失效
事后复盘最容易被跳过的动作
很多团队止步于“代码修好了”,但没动数据库层面的防御纵深。真正卡住后续攻击的,往往是那些没人记得配置的细节。
- 启用数据库的查询审计功能(MySQL 8.0 的
audit_log插件、PostgreSQL 的log_statement = 'all'),并把日志接入 SIEM - 给所有应用数据库账号加
max_connections和max_statement_time限制,防爆破和盲注耗尽资源 - 把本次 payload 加入 CI/CD 的 SAST 扫描规则库,下次提交含类似字符串的代码直接阻断
应急流程不是修一个点,而是让下一次同类攻击至少多撞三次墙。最常被忽略的是数据库权限回收和审计日志落地——它们不改一行应用代码,却能让你在攻击发生时,第一时间看清对方到底读了哪张表、查了哪些字段。

















