先确认mysql通用日志是否启用(show variables like 'general_log%'),若为on且log_output有效,则grep筛选union select、or 1=1、sleep(等特征,并结合时间密集度、报错信息及非人化sql模式综合研判。

查 MySQL 通用日志里有没有可疑 SQL
通用日志(general_log)是 MySQL 原生记录所有客户端请求的开关,只要它开着,SELECT、UNION SELECT、OR 1=1、SLEEP(5) 这类典型注入特征就会原样落盘。不是靠猜,是直接翻日志。
先确认是否启用:SHOW VARIABLES LIKE 'general_log%';。如果 general_log 是 ON,且 general_log_file 指向某个路径(比如 /var/log/mysql/general.log),就立刻去翻这个文件。
- 用
grep -i "union.*select\|or 1=1\|sleep(\|waitfor\|xp_cmdshell" /var/log/mysql/general.log快速筛出高危模式 - 注意时间戳密集段——攻击者扫表或爆库时,往往在几秒内发几十条带
ORDER BY或UNION的请求 - 别只看成功语句;
ERROR 1064或ERROR 1222(列数不匹配)这类报错也常出现在盲注探测阶段
用 PDO 封装层自动记录带参数的完整查询
靠数据库日志有延迟、要开开关、还可能被清空。更稳的方式是在 PHP 层拦截:所有 execute() 调用前,把绑定参数和原始 SQL 拼成可读字符串记进文件。
关键不是记“执行了什么”,而是记“执行了什么 + 参数是什么”。比如 SELECT * FROM users WHERE id = ? 绑定 [123],日志里就得是 SELECT * FROM users WHERE id = 123,否则看不出拼接风险。
- 重写
PDOStatement::execute()方法,在调用父方法前用error_log()写入[$timestamp] SELECT: SELECT * FROM users WHERE id = 123\n - 对
query()这种裸 SQL 执行,必须额外检查 SQL 字符串里是否含' OR '、" UNION "等模式,命中即告警 - 日志路径别放在 Web 可访问目录,比如写到
/var/log/php/db-audit.log,并设好权限(chmod 600)
审计日志时重点盯这些“不像人写的”SQL 模式
真实业务 SQL 有规律:字段名固定、WHERE 条件多为等值或范围、很少嵌套子查询。注入流量则相反——它机械、重复、试探性强。
以下模式一出现,基本不用再验,就是可疑痕迹:
-
SELECT ... FROM information_schema.tables—— 攻击者在探库结构 -
SELECT ... FROM (SELECT COUNT(*), CONCAT(..., FLOOR(RAND(0)*2)) x ... GROUP BY x)—— 经典报错注入 payload - 同一 IP 在 1 分钟内发出 20+ 条
SELECT ... ORDER BY N(N 从 1 递增到 20)—— 列数探测 - SQL 中出现
CHAR(45,45,32)(即--的 ASCII 编码)或0x2d2d20—— 绕过简单关键词过滤
为什么不能只依赖 error_log 或 try/catch 日志
PHP 层捕获的异常日志(比如 PDOException)只记录失败查询,但很多注入根本不会报错:盲注走的是响应时间差或布尔逻辑,联合查询注入只要列数对得上,就静默返回数据。
更麻烦的是,有些团队开了 display_errors = Off 但忘了关 log_errors,结果错误全打到 php_error.log 里,而里面混着大量 Warning 和 Notice,SQLSTATE[42000] 这类关键错误反而被淹没。
- 真正有效的审计日志必须包含:原始 SQL 字符串、绑定参数、执行耗时、客户端 IP、HTTP Referer(如果有)
- 只记
SQLSTATE或错误消息,等于把攻击者留下的脚印擦掉一半 - 如果用的是 mysqli 扩展,记得它没有统一的 execute 钩子,得在每个
mysqli_query()调用前手动插日志,漏一处就少一处证据
日志能告诉你“谁在试”,但不能代替代码修复。看到 UNION SELECT 出现在日志里,第一反应不该是加个 str_replace() 过滤,而是立刻定位到对应 controller 里那行 mysqli_query($conn, "SELECT ... WHERE id = " . $_GET['id']) —— 那才是根。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











