1 序言
思路:根据待输出的关键字段名称进行不可逆算法的(离线式)脱敏。
2 步骤
2.1 修改本工程的日志框架为 Log4j2
slf4j.version = 1.7.25
log4j.version = 2.13.3
<!-- log [start] -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- log [end] -->
2.2 基于Log4j2自定义 StringLayout
Log4j2Rule
import com.google.common.collect.Lists;
import java.util.List;
public class Log4j2Rule {
public static List<String> regulars = Lists.newArrayList();
public static final String KEY_REGEXP = "@#.*?#@";
public Log4j2Rule() {
}
static {
regulars.add("@#.*?#@");
}
}
CustomPatternLayout
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.johnnyzen.Log4j2Rule;
import java.nio.charset.Charset;
import java.util.Iterator;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Plugin(
name = "CustomPatternLayout",
category = "Core",
elementType = "layout",
printObject = true
)
public class CustomPatternLayout extends AbstractStringLayout {
public static final Logger logger = LoggerFactory.getLogger(CustomPatternLayout.class);
private PatternLayout patternLayout;
protected CustomPatternLayout(Charset charset, String pattern) {
super(charset);
this.patternLayout = PatternLayout.newBuilder().withPattern(pattern).build();
}
public String hideMarkLog(String logStr) {
try {
if (!StringUtils.isBlank(logStr) && !CollUtil.isEmpty(Log4j2Rule.regulars)) {
Iterator var2 = Log4j2Rule.regulars.iterator();
while(var2.hasNext()) {
String regular = (String)var2.next();
if (ReUtil.count(regular, logStr) > 0) {
logStr = matchingAndEncrypt(logStr, regular);
}
}
return logStr;
} else {
return logStr;
}
} catch (Exception var4) {
logger.info(">>>>>>>>> 脱敏处理异常 ERROR:{}", var4);
return logStr;
}
}
private static String matchingAndEncrypt(String msg, String regExp) {
return ReUtil.replaceAll(msg, regExp, (matcher) -> {
String group = matcher.group();
if (org.apache.commons.lang.StringUtils.isNotEmpty(group)) {
group = StrUtil.sub(group, 2, -2);
return SecureUtil.sha256(group);
} else {
return msg;
}
});
}
@PluginFactory
public static Layout createLayout(@PluginAttribute("pattern") String pattern, @PluginAttribute("charset") Charset charset) {
return new CustomPatternLayout(charset, pattern);
}
public String toSerializable(LogEvent event) {
return this.hideMarkLog(this.patternLayout.toSerializable(event));
}
}
2.3 修改日志的配置策略 (log4j.properties)
appender.{accessRollingFile/...}.layout.type=CustomPatternLayout
2.4 定义对象脱敏dValueFilter : TargetClassDesensitizationValueFilter
import com.alibaba.fastjson2.filter.ValueFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import org.springframework.util.ObjectUtils;
import java.util.ArrayList;
import java.util.List;
public class TargetClassDesensitizationValueFilter implements ValueFilter {
private final static Logger logger = LoggerFactory.getLogger(VehicleDesensitizationValueFilter.class);
/**
* 脱敏规则
*/
public final static String DESENSITIZATION_REGEXP = "@#.*?#@";
/** 用于 String.format(DESENSITIZATION_TEMPLATE, targetField) 的脱敏格式模板 **/
public final static String DESENSITIZATION_TEMPLATE = "@#%s#@";
public static String TARGET_FIELD_PARAM = "idCard";
public static String TARGET_FIELD_LIST_PARAM = "idCardList";
/**
* 对象脱敏 | 基于 业务中台的 Layout : @#%s#@
* @param object
* @param propertyName
* @param propertyValue
* @return
*/
@Override
public Object apply(Object object, String propertyName, Object propertyValue) {
logger.debug("object: {}, propertyName:{}, propertyValue: {}", object, propertyName, propertyValue);
Object newPropertyValue = null; // 只要字段名中包含 TARGET_FIELD_PARAM ,则:值输出为 returnValue;
if (propertyName.equals(TARGET_FIELD_PARAM)) {
if(propertyValue instanceof String){
String targetFieldValue = (String) propertyValue;
return String.format(DESENSITIZATION_TEMPLATE, targetFieldValue);// 返回修改后的属性值
} else {
//Do Nothing
}
} else if(propertyName.equals(TARGET_FIELD_LIST_PARAM)) {
if( (!ObjectUtils.isEmpty(propertyValue)) && (propertyValue instanceof List) ){
List list = (List) propertyValue;
Object firstElement = list.get(0);
if(firstElement instanceof String){// list's data structure is List<String>
List<String> newTargetFieldValueList = new ArrayList<>();
targetFieldValueList.stream().forEach( targetFieldValue -> {
newTargetFieldValueList.add(String.format(DESENSITIZATION_TEMPLATE, targetFieldValue));
});
newPropertyValue = newTargetFieldValueList;
return newPropertyValue;
} else {
//Do Nothing
}
} else {
//Do Nothing
}
}
return propertyValue;
}
/**
* 文本脱敏 (脱敏策略应用于文本) | 基于 base64
* @return
*/
public static String textDesensitization(String content){
if(ObjectUtils.isEmpty(content)){
return null;
} else {
if(content.contains(TARGET_FIELD_PARAM) || content.contains(TARGET_FIELD_LIST_PARAM)){
return "#DESENSITIZATION_START#" + Base64Utils.encodeToString(content.getBytes()) + "#DESENSITIZATION_END#";
}
}
return content;
}
}
2.5 修改明文格式输出日志的代码为脱敏输出格式
将含 targetFiled 的日志明文 转密文
sample: “3343243536” => "@#3343243536#@"
场景1: 打印基本数据类型、字符串
logger.info("targetFiled: {}", String.format("@#%s#@", "3343243536"));
场景2: 打印对象
{"vin": "436345345"}
logger.info("targetObject: {}", JSON.toJSONString(pageRequest, new TargetClassDesensitizationValueFilter()) );
2.6 打印效果
public class LogDesensitizationTest {
private final static Logger logger = LoggerFactory.getLogger(LogDesensitizationTest.class);
@Test
public void test(){
Map<String, Object> params = new HashMap<>();
params.put("idCard", "35355");//{"idCard":"c69c21ce30afa92d6df9606c906fc1a4982922ae64982e20018ada97a3b1174a"}
logger.info("idCard: {}", com.alibaba.fastjson2.JSON.toJSONString(params, new TargetClassDesensitizationValueFilter()));//
logger.info("idCard: {}", TargetClassDesensitizationValueFilter.textDesensitization(String.format("idCard:43534534")));//#DESENSITIZATION_START#aWRDYXJkOjQzNTM0NTM0#DESENSITIZATION_END#
}
}
标签:return,String,实践,log4j,org,import,日志,public,脱敏
From: https://www.cnblogs.com/johnnyzen/p/17569379.html