在java日志拦截器中过滤敏感字段,核心是在日志记录前对json请求/响应体做脱敏处理:通过jackson解析jsonnode,递归匹配白名单字段(如password、mobile等),不区分大小写替换为掩码,避免正则误伤;禁止直接打印原始对象,应封装logutils或结合@logmask注解+aop实现精准脱敏,并按环境与日志级别差异化控制掩码强度。

在 Java 的日志拦截器中过滤敏感字段,核心是**在日志记录前对日志内容做脱敏处理**,而不是依赖日志框架本身的配置(如 Logback 的 PatternLayout 无法自动识别“密码”字段)。关键在于:拦截请求/响应体、解析结构化数据(如 JSON)、识别并替换敏感字段值。
识别并提取待脱敏的敏感字段
不能仅靠字段名模糊匹配(比如含 “pwd” 就删),需结合业务语义和数据结构。常见策略:
- 定义明确的敏感字段白名单,如
["password", "pwd", "mobile", "phone", "idCard", "bankCard"],不区分大小写匹配 key - 对 JSON 请求体或响应体,使用轻量解析器(如 Jackson 的
JsonNode或 FastJSON)递归遍历所有 key-value 对 - 避免正则全文匹配——容易误伤(如日志里出现 “password is not valid” 这类文本)
在拦截器中统一做 JSON 脱敏
以 Spring MVC 的 HandlerInterceptor 为例,在 afterCompletion 或 preHandle 中处理日志前的数据:
- 若请求体是 JSON,用
ObjectMapper反序列化为JsonNode,遍历所有节点,对匹配到的敏感 key 的 value 替换为"***"或掩码(如手机号保留前3后4:"138****1234") - 脱敏后重新序列化为字符串用于日志输出,原始请求体保持不变(不影响业务逻辑)
- 示例片段(Jackson):
private JsonNode maskSensitive(JsonNode node) { if (node.isObject()) { ObjectNode objectNode = (ObjectNode) node; Iterator<map.entry jsonnode>> fields = objectNode.fields(); while (fields.hasNext()) { Map.Entry<string jsonnode> entry = fields.next(); String key = entry.getKey().toLowerCase(); if (SENSITIVE_KEYS.contains(key)) { objectNode.set(entry.getKey(), textNode("***")); } else { maskSensitive(entry.getValue()); } } } else if (node.isArray()) { node.forEach(this::maskSensitive); } return node; }</string></map.entry>
避免日志框架直接打印原始对象
很多开发者习惯直接 log.info("req: {}", request),若 request 是未脱敏的 POJO 或 Map,会触发 toString() 输出全部字段。正确做法:
- 禁止对可能含敏感信息的对象直接打 log —— 尤其是
HttpServletRequest.getParameterMap()、@RequestBody对象 - 封装专用的日志工具方法,如
LogUtils.logSafeRequest(requestBody),内部强制走脱敏逻辑 - 对 Controller 层入参,可用自定义注解(如
@LogMask)+ AOP 在打印前拦截并脱敏,比全局拦截器更精准
补充建议:分环境与分级控制
脱敏不是“一刀切”,应兼顾可观测性与安全性:
- 开发/测试环境可开启“半脱敏”(如密码显示为
"pwd_abc123"前缀 + 掩码),方便排查;生产环境严格全掩码 - ERROR 级别日志可保留部分上下文(如脱敏后的手机号前缀),WARN/INFO 级别按策略彻底隐藏
- 审计日志(如有)需单独存储、加密、权限隔离,不与普通应用日志混用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











