微服务-日志脱敏
场景
在很多情况下,都需要对我们输出的数据进行脱敏,比如
- 日志脱敏
- 数据库数据脱敏
这里我们实现日志脱敏
目标
- 减少对代码的入侵
- 可扩展性
logback 中实现日志脱敏
- 自定义 encoder: SensitivePatternLayoutEncoder
- 自定义 PatternLayout: SensitivePatternLayout
SensitivePatternLayoutEncoder
public class SensitivePatternLayoutEncoder extends PatternLayoutEncoderBase<ILoggingEvent> {
@Override
public void start() {
PatternLayout patternLayout = new SensitivePatternLayout();
patternLayout.setContext(context);
patternLayout.setPattern(getPattern());
patternLayout.setOutputPatternAsHeader(outputPatternAsHeader);
patternLayout.start();
this.layout = patternLayout;
super.start();
}
}
SensitivePatternLayout
public class SensitivePatternLayout extends PatternLayout {
private static List<SensitiveStrategy> patterns = new ArrayList<>();
private volatile boolean init = false;
@Override
public String doLayout(ILoggingEvent event) {
String message = super.doLayout(event);
if (!init){
init = true;
//添加默认策略
addDefaultPatterns();
}
if (patterns != null) {
for (SensitiveStrategy sensitiveStrategy : patterns) {
Matcher matcher = sensitiveStrategy.pattern().matcher(message);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String group = matcher.group(0);
matcher.appendReplacement(sb, sensitiveStrategy.resolve(group));
}
matcher.appendTail(sb);
message = sb.toString();
}
}
return message;
}
/**
* 默认规则
*/
private void addDefaultPatterns() {
addPattern(new EmailSensitiveStrategy());
}
/**
* 向后添加规则
* @param sensitiveStrategy
*/
public static void addPattern(SensitiveStrategy sensitiveStrategy) {
patterns.add(sensitiveStrategy);
}
/**
* 向前添加规则,优先级越高
* @param sensitiveStrategy
*/
public static void addFirstPattern(SensitiveStrategy sensitiveStrategy) {
patterns.add(0,sensitiveStrategy);
}
}
实现匹配策略
定义策略接口:
public interface SensitiveStrategy {
/**
* 匹配正则
* @return
*/
Pattern pattern();
/**
* 处理匹配之后结果
* @param message 匹配出来的字符
* @return
*/
String resolve(String message);
}
EmailSensitiveStrategy
匹配邮箱
public class EmailSensitiveStrategy implements SensitiveStrategy{
@Override
public Pattern pattern() {
//匹配email的正则表达式
return Pattern.compile("\\b([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\\.[a-zA-Z0-9_-]{2,3}){1,2})\\b");
}
@Override
public String resolve(String message) {
return DesensitizedUtil.email(message);
}
}
PhoneSensitiveStrategy
匹配手机号
public class PhoneSensitiveStrategy implements SensitiveStrategy{
@Override
public Pattern pattern() {
//匹配手机号正则
return Pattern.compile("\\b1[3-9]\\d{9}\\b");
}
@Override
public String resolve(String message) {
return DesensitizedUtil.mobilePhone(message);
}
}
logback.xml配置
使用自定义的 encoder
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="com.x.x.mvc.log.SensitivePatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
测试
@Slf4j
public class LogMain {
static {
//这里可以在项目中独自添加实现
//配置手机号
SensitivePatternLayout.addFirstPattern(new PhoneSensitiveStrategy());
}
public static void main(String[] args) throws JoranException {
log.debug("User 13767568987 accessed account with ID 1313132@qq.com and other email 37489339@gmail.com");
}
}
结果:
DEBUG com.LogMain - User 137****8987 accessed account with ID 1******@qq.com and other email 3*******@gmail.com
good luck!