环境:Spring Boot3.2.5
1. 简介
在当前的数据保护时代,我们必须高度重视个人敏感数据的处理与记录。鉴于数据量庞大,我们在记录这些信息时,必须格外小心,采取适当措施来屏蔽或保护用户的敏感信息,以保障他们的隐私权不受侵犯。
本篇文章,我将详细介绍如何使用 Logback 隐藏日志中的敏感数据。虽然这种方法是日志文件的最后一道防线,但它并不是解决问题的最终方案。敏感数据是指任何需要防止未经授权访问的信息。这可能包括任何个人身份信息,如社会安全号码、银行信息、登录凭据、地址、电子邮件等。
Logback 是 Java 社区使用最广泛的日志框架之一。它取代了其前身 Log4j。Logback 的实现速度更快,配置选项更多,而且在归档旧日志文件方面更具灵活性。
接下来,我们将在登录应用程序日志时屏蔽属于用户的敏感数据。
2. 实战案例
2.1 环境准备
准备实体对象
public class User {private Long id ;private String name ;private String address ;private String phone ;private String password ;private String email ;// getters, setters}
我们后续将对上面的name,phone,password,email进行脱敏处理。
接口定义
("/login")public User login() throws Exception {// TODOUser user = new User(1L, "张三", "新疆", "1399999999", "123456789", "xxxooo@qq.com") ;logger.info("用户信息: {}", new ObjectMapper().writeValueAsString(user)) ;return user ;}
在正常情况下访问上面的接口日志输出如下:

接下来,我们将要处理这里的敏感字段。
2.2 自定义PatternLayout
PatternLayout类可以通过模式字符串配置的灵活布局。这个类的目标是格式化一个ILoggingEvent并以{#link String}的形式返回结果。结果的格式取决于转换模式。
public class MaskingPatternLayout extends PatternLayout {private Pattern multilinePattern;private List<String> maskPatterns = new ArrayList<>();public void addMaskPattern(String maskPattern) {maskPatterns.add(maskPattern);multilinePattern = Pattern.compile(maskPatterns.stream().collect(Collectors.joining("|")), Pattern.MULTILINE);}@Overridepublic String doLayout(ILoggingEvent event) {return maskMessage(super.doLayout(event));}private String maskMessage(String content) {if (multilinePattern == null) {return content;}StringBuilder sb = new StringBuilder(content);Matcher matcher = multilinePattern.matcher(sb);while (matcher.find()) {IntStream.rangeClosed(1, matcher.groupCount()).forEach(group -> {if (matcher.group(group) != null) {IntStream.range(matcher.start(group), matcher.end(group)).forEach(i -> sb.setCharAt(i, '*'));}});}return sb.toString();}}
PatternLayout.doLayout()的实现负责在应用程序的每条日志信息中屏蔽匹配的数据,前提是这些数据与配置的模式之一相匹配。
接下来就可以在logback-spring.xml中配置;logback.xml 中的 maskPatterns 列表可构建多行模式。如果它以属性列表的形式出现,那么每个配置项都会调用 addMaskPattern。
2.3 配置Appender
<appender name="mask" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="com.pack.sensitive.log.MaskingPatternLayout"><maskPattern>\"name\"\s*:\s*\"(.*?)\"</maskPattern><maskPattern>\"phone\"\s*:\s*\"(.*?)\"</maskPattern><maskPattern>\"password\"\s*:\s*\"(.*?)\"</maskPattern><maskPattern>([\w.-]+@[\w.-]+\.\w+)</maskPattern><pattern>%d{22:mm:ss} %-5level %logger Line:%-3L - %msg%n</pattern><charset>UTF-8</charset></layout></encoder></appender>
这里我添加了4个模式用来匹配上面提到的4个字段。有个该配置后再次进行访问上面的接口

控制台日志输出

正确的将我们需要处理的字段进行了脱敏。
如果我们是直接打印的对象呢?
User user = new User(1L, "张三", "新疆", "1399999999", "123456789", "xxxooo@qq.com") ;logger.info("用户信息: {}", new ObjectMapper().writeValueAsString(user)) ;logger.info("直接打印对象: {}", user) ;
日志输出

对于这种情况,我们还需要定义更多的模式,如下:
<maskPattern>name\s*=\s*(.*?),</maskPattern><maskPattern>password\s*=\s*(.*?),</maskPattern>
再次访问接口

正确的脱敏了此种情况。
以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
推荐文章
一文彻底玩转@RequestMapping,高级用法你未必知道
Spring Boot REST API版本控制的方案及选择
重磅!Spring Boot3.4 结构化日志,强大的日志记录技术
弃用Spring Cache!首选多级缓存框架JetCache
【难!难!难!】Spring夺命10连问,你能答上几个?有代码!
Spring Bean中注入实例变量HttpServletRequest到底是不是线程安全的?
Spring Cache秒杀百万级并发!90%的项目都在用的性能优化秘密武器!



