日志脱敏方案最容易翻车的地方,不在正则写得漂亮不漂亮,在范围划得够不够宽。回头看那些出事的日志,问题那条里面往往压根没出现“手机号”这三个字——它被塞在 URL 参数里、裹在一段错误堆栈里,或者躺在用户自己敲进备注框的那句话里。字段清单列得再工整,只盯着结构化表结构去做,等于大门上了三把锁、窗户全开着。

日志脱敏方案的第一步是把范围划出来,不是打开编辑器写正则
范围其实有两层。一层是“哪些日志”:应用日志、访问日志、慢查询日志、网关日志、容器标准输出、崩溃上报、审计日志,很多人只记得业务代码里那句 logger.info 打出来的东西,忘了 nginx 默认的 access_log 一行里就带着完整请求行。另一层是“哪些环节”:写入、传输、落盘、归档、备份、导出、给测试、进第三方平台。任何一环漏掉,前面的活儿都白干。这两张清单先老老实实列出来,比一上来就写十条正则管用得多。
第一类,URL 查询串和请求头,最容易被当成“不算字段”漏过去
access log 的默认格式里 $request 是带 query string 的,用户在前端填的东西如果走了 GET,或者表单提交后跳转带了参数,手机号、邮箱、订单号、甚至连 token 都在里头。请求头更隐蔽:Referer 会带上来源页的搜索词,X-User-Id、X-Phone 这种自定义头前端随手就塞进去了,谁也没在字段表上登记过。做法上,网络入口拦一道比每个应用各写一遍靠谱:nginx 的 log_format 只保留 $request_method 和 $uri,不写 $request;确实要留 query 的,用 map 把敏感参数整段换掉。应用侧再补一层兜底,别指望一处覆盖全部。
第二类,异常堆栈和上游返回的错误体
堆栈本身不敏感,麻烦在于捕获异常时顺手把整个上下文都拼进了 message——请求体原文、SQL 语句、上游返回的那段 JSON。SQL 里能带出用户搜的词,支付、短信这类上游的错误响应,返回的经常是脱敏之前的明文。这种东西平时不出事,一出事就是最完整的一份数据,比自己辛辛苦苦攒的日志全多了。稳妥的写法:异常日志只记异常类型、堆栈和 trace id,业务参数走单独的 debug 开关且默认关掉;确实要记错误响应,先截长度再脱一次敏。
第三类,自由文本,正则基本救不了
客服工单的备注、用户提交的反馈、搜索框里敲的词、图片上传的文件名、收货地址那一栏。这些字段没法定 schema,用户想怎么写就怎么写,你也没法在写入前拦住。指望一条“18 位数字”的正则兜住是不现实的——手机号有空格的、带加号的、带括号的、写成中文数字的,还有人把证件号拆成两段填。这类字段我的建议是优先级排最前面:能不落原文就不落,只记长度或者哈希;必须留的,写入前过一遍规则加人工抽检,别想着一次配好永不管。
日志脱敏方案的边界,脱敏不等于删干净
脱敏有两个目的,一是合规,二是别把日志变成一堆没法排查的废数据。手机号留前几位后几位、邮箱留域名、IP 留网段,具体留到哪一位要按业务和适用的法规口径来定,拿不准就以服务商或官方页面说明为准,别自己想当然。另外一致性很重要:同一个用户在同一个 trace 里要能被串起来,所以用带固定盐的哈希比随机替换好使,盐存在哪、怎么轮换得单独定个规矩。IP 到底算不算个人信息,不同口径说法不一样,这块同样以官方说明为准。
副本才是真正的漏洞:备份、归档、测试数据和导出文件
线上日志做了脱敏,测试环境里那批从线上导出来的样本往往还是原文;日志平台归档到对象存储,脱敏规则没跟着同步过去;客服要导一份 csv 给业务做分析,导出功能压根没走那层中间件。这些地方都能把前面所有努力一次性绕过去,而且还特别难被发现,因为没人会在看报表的时候想起手边这个文件是哪来的。稳妥点,把脱敏收敛到一处统一处理,宁可多一次转发、多几十毫秒延迟。第三方 SDK 和外部日志服务的默认采集项,也得单独翻一翻。
上线之前,拿这张清单走一遍
挑一条真实请求,从入口跟到底,看落下来的日志里参数是不是原样;单独造一次异常,看堆栈和错误体里有没有夹带原文;跑一次导出,看 csv 是不是明文;从备份恢复一份,再查一遍同样的东西;脱敏规则的改动要进回归用例,别改一次漏一次;最后给开发一份“日志里不许出现什么”的短清单,贴在他们天天看得到的地方,比写十页规范有人看。这几件做完,八成的问题就堵住了。
这类事没有做一次就一劳永逸的版本。范围先划清,副本先管住,剩下的靠定期抽查——随手从线上捞一条日志看一眼,比死守那份规则列表有用得多。
【版权声明】:本站内容若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!