Spring Boot中如何实现日志脱敏?

日志,作为在日常开发中用来进行故障排查、性能监控、操作审计的重要工具,在程序设计过程中是比不可少的存在,但是在某些场景中,日志中可能会包含有很多的敏感信息,例如用户名、密码、身份证号、手机号、信用卡信息等等信息。如果这些敏感信息出现在日志中,可能会导致信息泄露或者是出现系统安全隐患,因此,日志脱敏操作就显得尤为重要了,下面我们就来结合Spring Boot看看如何在Spring Boot中实现对日志的脱敏操作。
日志脱敏
??所谓的日志脱敏就是指在日志记录的过程中将原本包含有敏感信息的日志通过内容替换、内容遮掩等方式避免敏感信息被暴露的的一种手段,一般情况下,日志脱敏的方式主要有如下几种。
- 替换成固定字符:例如,将密码替换为******。
- 部分字符保留:例如,将信用卡号的前四位和后四位保留,中间的部分用星号替代。
- 删除敏感信息:将日志中的敏感信息完全移除,记录为“[敏感数据]”。
SpringBoot中实现日志脱敏
??我们知道,在Spring Boot中默认通过SLF4J+Logback来实现日志的记录,Logback是允许我们来自定义日志的输出格式的,也就是说我们可以通过实现自定义的日志脱敏过滤器来进行日志脱敏操作,如下所示。
自定义的MaskingPatternLayout类
??我们可以继承PatternLayoutBase类来实现一个自定义的日志格式化输出的过滤器类,如下所示。
import ch.qos.logback.classic.pattern.PatternLayoutBase;
import org.apache.commons.lang3.StringUtils;
public class MaskingPatternLayout extends PatternLayoutBase {
@Override
protected String doLayout(Object event) {
String message = event.toString();
return maskSensitiveData(message);
}
// 脱敏逻辑
private String maskSensitiveData(String message) {
// 可以根据需要实现更多的脱敏规则
if (message.contains("password")) {
message = message.replaceAll("password=[^&]*", "password=******");
}
if (message.contains("cardNumber")) {
message = message.replaceAll("cardNumber=[0-9]{13,19}", "cardNumber=******");
}
return message;
}
}
修改配置文件
??接下来就可以将这个脱敏的过滤器配置到LogBack的配置文件中,如下所示,在logback-spring.xml配置文件中添加自定义的日志脱敏过滤器。
<configuration>
<!-- 配置自定义的MaskingPatternLayout -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss} - %msg%n
</pattern>
<layout class="com.example.logging.MaskingPatternLayout"/> <!-- 引用自定义的脱敏类 -->
</encoder>
</appender>
<!-- 定义日志级别和输出 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
??这样我们就可以将日志中的密码以及信用卡号进行脱敏处理,当然除了这种方式之外,我们还可以通过AOP日志切面的方式来实现日志脱敏操作,如下所示。
使用AOP切面进行日志脱敏
??首先我们需要创建一个日志脱敏的切面类,如下所示,我们可以根据需求来修改切点,或者是我们可以通过自定义注解的方式来动态的指定切点位置。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogMaskingAspect {
@Pointcut("execution(* com.example..*.*(..))") // 设定切点,根据需求修改
public void logPointcut() {}
@Before("logPointcut()")
public void beforeMethod() {
// 在这里做脱敏操作,可以使用正则替换掉敏感数据
System.out.println("日志脱敏前处理");
}
// 可以在这里根据参数或者其他信息对日志内容进行脱敏操作
private String maskSensitiveInfo(String logMessage) {
if (logMessage.contains("password")) {
logMessage = logMessage.replaceAll("password=[^&]*", "password=******");
}
return logMessage;
}
}
??然后我们可以将该切面注入到Spring Boot的容器中,这样我们就可以对日志中的密码进行脱敏了,如下所示。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
@Bean
public LogMaskingAspect logMaskingAspect() {
return new LogMaskingAspect();
}
}
??当然除了上面的这些方式之外,有些日志依赖库本身就提供了通过配置的方式来实现日志脱敏的操作,如果我们在业务开发中不想手动的去实现脱敏操作,我们也可以使用这些外部依赖库来实现日志脱敏操作,如下所示,是一些在日常开发中比较常用的日志脱敏库。
- log4j2-slf4j-logmask:适用于 Logback 或 log4j2,支持自动脱敏。
- logmask:一个轻量级的日志脱敏库,支持 Logback 配置。
- Logback Masking Appender:专门针对 Logback 提供的日志脱敏库。
- Slf4j-LogMasker:基于 SLF4J 的日志脱敏库,支持常见敏感数据的脱敏。
总结
??日志脱敏操作是保证敏感信息不被泄露的重要手段之一,在Spring Boot应用中,我们可以通过自定义日志处理器、AOP拦截器、第三方框架等各种的手段来实现日志脱敏的操作。当然在实际开发中,我们可以根据自己的业务需求来选择合适的脱敏手段来保证敏感信息不被泄露,在保留了日志功能的前提下也提升了系统的安全性。