错误日志本身不记录sql或用户数据,但因应用错误配置、自定义函数拼接敏感信息、load data路径暴露、误用其他日志或调试输出等,可能导致敏感信息间接泄露;需通过撤销file/process/execute权限、禁用super_priv、限制log_error_verbosity≤3、确保log_error文件权限为600及隔离日志路径来防控。

错误日志(error_log)本身不记录SQL语句或用户数据,但某些配置不当或异常场景下,敏感信息可能间接泄露——比如应用层错误堆栈被写入日志、自定义错误消息含明文密码、或错误触发的调试输出暴露字段内容。单纯靠权限设置无法直接过滤错误日志内容,但可通过权限控制**源头行为**,大幅降低敏感信息进入错误日志的风险。
为什么错误日志里会出现敏感数据?
MySQL 错误日志默认只记启动、关闭、崩溃、连接拒绝等系统级事件,不记 SQL。但以下情况会让敏感内容“绕道”进去:
- 应用代码把
SELECT password FROM users的完整报错(含 SQL 文本)直接打到 MySQL 错误日志(极少见,通常说明应用日志配置错误) - 触发了自定义存储过程或函数的错误,而该函数内部拼接了含身份证号的提示消息,再用
SIGNAL抛出,部分版本会把 message 写入 error log -
LOAD DATA INFILE失败时,若路径含用户名或临时文件名,可能暴露路径结构(如/tmp/user_12345.csv) - 开启
general_log或slow_query_log后,错误日志虽不录 SQL,但其他日志文件可能被误当 error log 查看
用权限堵住敏感数据进日志的入口
真正起效的不是给用户设“不能写日志”权限(MySQL 没这权限),而是限制用户执行那些容易触发敏感输出的操作:
- 撤销
FILE权限:防止用户通过LOAD DATA INFILE或SELECT ... INTO OUTFILE触发路径暴露或构造恶意错误。执行REVOKE FILE ON *.* FROM 'app_user'@'%'; - 禁用高危函数调用:对非 DBA 用户,回收
EXECUTE权限,避免其调用含敏感字符串拼接的自定义函数。检查函数定义是否含CONCAT('user:', user_id)类逻辑 - 限制
PROCESS权限:该权限允许查看其他线程的 SQL(SHOW PROCESSLIST),虽然不直写 error log,但若应用把PROCESSLIST输出当错误上下文打印,就可能带出敏感查询。执行REVOKE PROCESS ON *.* FROM 'app_user'@'%'; - 关闭
super_priv:拥有该权限的用户可动态修改log_error_verbosity或log_output,甚至把 general_log 写进 error log 文件。确保普通用户无此权限
配合配置项收紧日志行为
权限只是基础,必须搭配关键配置才能切断泄露链路:
- 确认
log_error_verbosity≤ 3(默认值):设为 4 或 5 会记录更多 SQL 上下文,增加泄露风险。运行SELECT @@log_error_verbosity;检查,必要时在[mysqld]中设log_error_verbosity = 3 - 禁用
log_error_suppression_list的误用:该变量用于屏蔽特定错误码,但如果填了错误的正则(如匹配所有含 "password" 的行),反而可能让本该被抑制的敏感错误漏出 - 不要把
log_error设为世界可读路径:确保log_error = /var/log/mysql/error.log所指文件属主为mysql,权限为600。否则即使没敏感内容,文件本身也可能被未授权读取 - 避免在错误处理中调用
GET DIAGNOSTICS并拼接敏感字段:这是应用层问题,但 DBA 可审计存储过程,发现类似SET @msg = CONCAT('Failed for user ', user_id); SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @msg;就要提醒开发改掉
最易被忽略的是:错误日志本身不记录数据,但它是整个日志体系的“信任锚点”。一旦其他日志(如 slow log)被误配成和 error log 同路径,或应用把 query trace 写进 error log,权限再严也拦不住。务必核对 log_output 值是否为 FILE(而非 TABLE 或 NO),并确认所有日志文件路径相互隔离。











