必须启用 audit_log_format = new_record,因其仅记录操作元信息(用户、时间、ip等),不落盘sql文本及敏感参数,避免明文泄露;需搭配 audit_log_policy = logins 或 queries、独立高权限日志路径、加密传输与字段脱敏,否则审计日志反成风险入口。

审计日志本身记录的是操作行为,但若配置不当,它反而会成为敏感数据泄露的新入口——比如把 SELECT * FROM user_info 的完整结果写进日志,或把含身份证、手机号的 SQL 语句原样落盘。
audit_log_format = NEW_RECORD 为什么必须启用
MySQL 企业版的 audit_log 插件默认使用旧格式(OLD_RECORD),会把完整 SQL 文本(含 WHERE 条件里的明文手机号、身份证号)直接记入日志文件。这等于把脱敏前的数据又存了一遍。
必须显式切换为新格式:
SET GLOBAL audit_log_format = 'NEW_RECORD';
该格式只记录操作元信息:用户、时间、IP、数据库名、表名、操作类型(SELECT/UPDATE)、影响行数,不记录 SQL 文本和参数值。即使攻击者拿到日志文件,也看不到任何敏感字段内容。
注意:NEW_RECORD 格式需 MySQL 5.7.28+ 或 8.0.13+,旧版本不支持,强行设置会报错 ERROR 1193 (HY000): Unknown system variable 'audit_log_format'。
audit_log_policy = ALL 是最危险的默认值
插件默认开启 ALL 策略,意味着所有连接、所有查询(包括 SELECT password_hash FROM users 这种高危语句)都会被记录。这不是审计,是“全量镜像”。
应严格按需收缩范围:
-
SET GLOBAL audit_log_policy = 'LOGINS';—— 只记录登录/登出事件,适合最小化场景 -
SET GLOBAL audit_log_policy = 'QUERIES';—— 记录所有查询,但必须搭配NEW_RECORD格式 + 日志路径权限收紧 - 绝不设为
ALL,尤其在生产环境
检查当前策略用:SELECT @@audit_log_policy;。如果返回 ALL,立刻调整。
audit_log_file 路径权限必须隔离
审计日志文件(如 /var/log/mysql/audit.log)一旦被任意用户读取,就等于交出全部操作凭证。常见错误是把它放在 MySQL 数据目录下(如 /var/lib/mysql/),而该目录通常对 mysql 用户可读,且可能被备份脚本一并拉走。
正确做法:
- 将
audit_log_file指向独立目录,如/var/log/audit/mysql/ - 执行:
chown root:root /var/log/audit/mysql&&chmod 700 /var/log/audit/mysql - 确认 MySQL 进程仍能写入:MySQL 启动用户(通常是
mysql)需对该目录有写权限,可用setfacl -m u:mysql:w /var/log/audit/mysql实现细粒度控制
避免使用 log_output = TABLE:虽然看似“不落地”,但 mysql.audit_log 表本质仍是数据库内可查对象,一旦账号越权或 SQL 注入成功,日志反成攻击跳板。
日志轮转与传输必须剥离原始内容
即便用了 NEW_RECORD,日志中仍含用户名、IP、库表名等上下文信息。若直接同步到 SIEM 或 ELK,需确保传输链路加密(TLS)、接收端做字段级脱敏(如自动掩码 IP 最后一段、哈希化用户名)。
关键动作:
- 禁用
audit_log_rotate_on_size的盲目滚动,改用外部工具(如logrotate)配合postrotate脚本对归档日志做 GPG 加密 - 导出前过滤:用
grep -v "user_info\|auth_token" /var/log/audit/mysql/audit.log.*清理误记录的关键词(临时兜底,非替代策略) - 永远不要在日志中出现
password、id_card、phone字样——哪怕只是表名或列名,都可能触发合规扫描告警
真正难防的不是技术配置,而是把“审计日志”当成“安全日志”来用:它只证明“谁干了什么”,不保证“干的事本身安全”。所以,audit_log 必须和最小权限、应用层加密、网络隔离一起生效,单独启用毫无意义。











