PHP日志敏感信息脱敏须在写入前结构化处理,避免str_replace误伤或漏脱;应递归遍历上下文数组按键名(如password、token、id_card等)掩码值为[REDACTED],Monolog可用Processor实现,JSON脱敏需在json_encode前完成。

PHP 日志中敏感信息脱敏的常见错误做法
直接用 str_replace 全局替换手机号、身份证、密码字段,看似简单,实则危险:可能误伤正常数字字段(如订单号、时间戳),或漏掉嵌套 JSON 中的敏感值。更严重的是,若日志已写入磁盘再读取清洗,等于敏感数据已在文件系统中明文存在过。
在日志写入前做结构化脱敏(推荐)
核心原则:不碰原始请求数据,只在构造日志消息时剥离/掩码敏感字段。适用于 error_log、monolog、file_put_contents 等所有写入方式。
- 对数组类日志上下文(如请求参数
$_POST、$_GET),用递归函数遍历键名匹配关键词(password、id_card、phone、token),值统一替换为[REDACTED] - 避免正则全量扫描字符串日志——性能差且易误匹配;结构化处理才能精准定位字段
- 若使用 Monolog,可自定义
Processor类,在__invoke中处理$record['context'],不影响原有日志格式 - 注意 JSON 日志场景:脱敏必须在
json_encode之前完成,否则会把整个 JSON 字符串当文本处理,失去字段级控制
哪些字段名该纳入默认脱敏名单
别只盯着“password”——实际攻防中,access_token、refresh_token、card_number、bank_account、email(部分合规场景需脱敏)都属于高危字段。建议维护一个可配置的键名白名单/黑名单:
- 强制脱敏键名(大小写不敏感):
password、pwd、token、secret、key、card、account、id_card、mobile、tel - 允许透传的例外字段(如
user_id、order_id)需显式加入白名单,避免误杀 - 注意框架习惯命名:Laravel 的
$request->all()可能含_token,ThinkPHP 的input()可能返回client_ip(无需脱敏)但含auth_code
已有日志文件的补救式脱敏(仅应急)
线上已产生含敏感信息的日志文件,不能直接删(审计要求),也不能靠人工 grep —— 效率低且不可重复。可用脚本批量重写:
立即学习“PHP免费学习笔记(深入)”;
- 用
sed -i或 PHP 脚本逐行处理,匹配形如"phone":"13812345678"的 JSON 片段,替换值部分(保留引号和结构) - 务必先备份原文件:
cp access.log access.log.bak,脱敏后验证 JSON 是否仍合法(可用json_decode(file_get_contents(...), true)测试) - 禁止对压缩日志(
.gz)直接操作;先解压、脱敏、再重新压缩,否则损坏文件 - 该方式无法修复已被轮转、删除或上传至远程日志平台(如 ELK)的数据——真正有效的只有事前拦截
str_replace 就完事,关键在时机(写入前)、粒度(字段级)、可维护性(配置化键名规则)。一旦日志落地,补救成本远高于预防。











