文章总结: 本文介绍了Java日志脱敏的必要性及四种主流实现方案,重点阐述基于日志框架的自定义PatternLayout和Log4j2RewriteAppender两种推荐方案。文章对比各方案的侵入性、维护成本与适用场景,给出正则替换规则及完整代码示例。结论建议优先采用无侵入的集中式脱敏方案以平衡安全性与维护成本。 综合评分: 92 文章分类: 数据安全,应用安全,安全开发,安全工具,解决方案
Java 日志脱敏方案落地实践
原创
静观云起 静观云起
码云精炼
2026年5月24日 00:38 广东
在小说阅读器读本章
去阅读
一 为什么需要做日志脱敏?
在金融、电商、医疗等业务系统中,日志是排查问题的核心依据,但同时也可能成为数据泄露的“重灾区”。日志中可能包含手机号、身份证号、银行卡号、密码、Token等敏感信息,若直接明文打印,一旦日志文件被非法访问(如服务器被入侵、内部人员越权查看),将导致严重的合规风险(违反《个人信息保护法》《数据安全法》)和用户隐私泄露。因此,对日志中的敏感字段进行脱敏处理,是Java系统生产环境必备的安全防护手段。
二 常见脱敏场景
| | | | | — | — | — | | 敏感类型 | 示例 | 典型脱敏规则 | | 手机号 | 13812345678 | 保留前3后4,138****5678 | | 身份证号 | 110101199901011234 | 保留前6后4,110101********1234 | | 银行卡号 | 6225880256888888 | 保留后4位: ************8888 | | 邮箱 | [email protected] | 保留前缀首字母+域名: z***@test.com | | 密码/token | sk_live_abc123xyz | 全量替换为 ****** |
三 主流实现方案
✅ 方案一:基于日志框架的自定义PatternLayout(推荐)
适用场景:Logback/Log4j2,集中式统一脱敏
核心思路:在日志序列化阶段拦截,对日志内容进行正则匹配并替换。
自定义实现类:
public class SensitiveMaskingLayout extends PatternLayout { private static final List<Pattern> SENSITIVE_PATTERNS = List.of( Pattern.compile("(\\d{3})\\d{4}(\\d{4})", // 手机号 Pattern.compile("(\\d{6})\\d{8}(\\d{4})"), // 身份证号 @Override public String doLayout(ILoggingEvent event) { String message = super.doLayout(event); return mask(message); } private String mask(String text) { String result = text; for (Pattern pattern : SENSITIVE_PATTERNS) { result = pattern.matcher(result) .replaceAll("$1****$2"); } return result; } }
logback.xml配置
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="com.xxx.SensitiveMaskingLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger - %msg%n </pattern> </layout> </encoder>
✅ 优点:无侵入、一次配置全局生效
❌ 缺点:正则复杂时可能影响性能
✅ 方案二:基于SLF4J MDC + 注解 + AOP
适用场景:仅对特定业务参数脱敏(如接口入参)
实现思路:
使用注解标记敏感字段
@Sensitive(type = SensitiveType.MOBILE) private String phone;
通过AOP在方法执行前对参数脱敏;
将脱敏后的数据放入MDC,日志中引用。
✅ 优点:精准控制、适合业务参数
❌ 缺点:侵入代码、维护成本高
✅ 方案三:日志脱敏工具类(最轻量)
适用场景:临时方案或局部日志处理
public class DesensitizeUtil { public static String mobile(String mobile) { return mobile == null ? null : mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); } }
// 引用工具类log.info("用户手机号:{}",DesensitizeUtil.mobile(user.getPhone()));
✅ 优点:简单直观
❌ 缺点:容易遗漏、不可控
✅ 方案四:Log4j2 RewriteAppender(企业级推荐)
Log4j2 原生支持日志重写,可在不修改业务代码的前提下完成脱敏
引入依赖log4j2:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.24.1</version></dependency>
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.24.1</version></dependency>
自定义RewritePlolicy:
package com.xxx.log;
import org.apache.logging.log4j.core.LogEvent;import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;import org.apache.logging.log4j.core.config.plugins.Plugin;import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import java.util.regex.Matcher;import java.util.regex.Pattern;
@Plugin(name = "SensitiveRewritePolicy", category = "Core", elementType = "rewritePolicy")public class SensitiveRewritePolicy implements RewritePolicy {
/** 手机号 */ private static final Pattern MOBILE = Pattern.compile("(?<=\\d{3})\\d{4}(?=\\d{4})");
/** 身份证 */ private static final Pattern ID_CARD = Pattern.compile("(?<=\\d{6})\\d{8}(?=\\d{4})");
@Override public LogEvent rewrite(LogEvent logEvent) { if (logEvent == null) { return logEvent; }
String message = logEvent.getMessage().getFormattedMessage(); String masked = mask(message);
return new Log4jLogEvent.Builder(logEvent) .setMessage(new SimpleMessage(masked)) .build(); }
private String mask(String text) { Matcher m1 = MOBILE.matcher(text); text = m1.replaceAll("****"); Matcher m2 = ID_CARD.matcher(text); text = m2.replaceAll("********"); return text; }
@PluginFactory public static SensitiveRewritePolicy createPolicy() { return new SensitiveRewritePolicy(); }}
log4j.xml配置
<?xml version="1.0" encoding="UTF-8"?><Configuration status="WARN">
<Appenders> <!-- 原始文件Appender --> <RollingFile name="FILE" fileName="/logs/app.log" filePattern="/logs/app-%d{yyyy-MM-dd}.log.gz"> <PatternLayout pattern="%d{HH:mm:ss} [%t] %-5p %c - %m%n"/> </RollingFile>
<!-- RewriteAppender --> <Rewrite name="REWRITE"> <AppenderRef ref="FILE"/> <RewritePolicy ref="SensitiveRewritePolicy"/> </Rewrite> </Appenders>
<Loggers> <Root level="info"> <AppenderRef ref="REWRITE"/> </Root> </Loggers>
</Configuration>
四 总结
| | | | | | — | — | — | — | | 方案 | 侵入性 | 维护成本 | 推荐指数 | | 自定义Layout | ⭐ | ⭐⭐ | ⭐⭐⭐⭐ | | AOP + 注解 | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | | 工具类 | ⭐⭐ | ⭐⭐ | ⭐⭐ | | RewriteAppender | ⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:码云精炼 静观云起 静观云起《Java 日志脱敏方案落地实践》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论