针对日志打印而不能泄露用户隐私需求,需要利用相应日志框架实现脱敏,本文基于log4j/logback,重写相应方法,匹配出正则并转换为脱敏后的日志。效果展示如下
{“name”:“李**”, “idNumber”:“110106********226X”,“mobile”:“130****2333”}
1.基于log4j/logback,重写log4j的MessageConverter类
import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class xxxLogConverter extends MessageConverter{
@Override
public String convert(ILoggeringEvent event){
String sourceLog = event.getFormattedMessage();
return logSecurity(sourceLog);
}
public String logSecurity(final String sourceLog){
return HideStrUtil.loghandle(sourceLog);
}
2.加入屏蔽逻辑
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HideStrUtil {
public static final String regexPhone = "1[3456789]\\d{9}";
public static final String regexCard = "([1-9]\\d{5}[1-9]\\d{3}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx])|([1-9]\\d{5}\\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\\d{3})";
// public static final String regexName = "[\u4e00-\u9fa5]{2,20}";
public static final String regexName = "(\\\"name\\\":\\\"|\\\"cust_name\\\":\\\"|\\\"NAME\\\":\\\"|\\\"CUST_NAME\\\":\\\"|name=|cust_name=|name:\\\"|cust_name:\\\")[\u4e00-\u9fa5]{2,20}";
public static final Pattern pattern = Pattern.compile("[0-9a-zA-Z]");
/**
* 整合手机号、身份证号和姓名的脱敏
* @param str
* @return
*/
public static String logHandle(String str) {
if (StringUtils.isNotBlank(str)) {
str = matchRegexAndHide(regexCard, str);
str = matchRegexAndHide(regexPhone, str);
str = matchRegexAndHide(regexName, str);
}
return str;
}
/**
* 隐藏身份证里的出生日期,隐藏手机号中间4位,隐藏姓名里除最后一位的其他信息
* @param str
* @return
*/
public static String hideMidStr(String str,String regex) {
String str2 = str;
if (StringUtils.isNotBlank(str)) {
if (str.length() == 18 && regexCard.equals(regex)) {
if (str.endsWith("X") || str.endsWith("x")){
StringBuilder s = new StringBuilder(str);
str2 = s.replace(6, 14, "********").toString();
return str2;
}
str2 = str.replaceAll("(\\d{6})\\d{8}(\\d{4})", "$1********$2");
} else if (str.length() == 11 && regexPhone.equals(regex)) {
str2 = str.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
} else if(regexName.equals(regex) && str.indexOf(":")!=-1){
String[] param = str.split(":");
if(param!=null && param.length==2){
String name = String.valueOf(param[1].charAt(1));
str2 = param[0] +":\""+StringUtils.rightPad(name, StringUtils.length(param[1])-1, "*");
}
}else{
String[] param = str.split("=");
if(param!=null && param.length==2){
String name = String.valueOf(param[1].charAt(0));
str2 = param[0] +"="+StringUtils.rightPad(name, StringUtils.length(param[1]), "*");
}
}
}
return str2;
}
/**
* 根据传入的正则进行匹配,并脱敏,返回脱敏结果
* @param regex
* @param str
* @return
*/
public static String matchRegexAndHide(String regex, String str) {
StringBuffer sb = new StringBuffer();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
while (matcher.find()){
String group = matcher.group();
if (!isNumOrLetter(str,group)){
matcher.appendReplacement(sb,hideMidStr(group,regex));
}
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* 获取匹配到关键词的前一个和后一个字符是否为数字或字母
* @return
*/
public static boolean isNumOrLetter(String msg, String key){
int index = msg.indexOf(key);
// System.out.println(index);
if (index != -1){
// 判断key前面一个字符
if(index != 0){
char preCh = msg.charAt(index-1);
// System.out.println(preCh);
Matcher match = pattern.matcher(preCh + "");
if(match.matches()){
return true;
}
}
// 判断key后面一个字符
char nextCh = msg.charAt(index + key.length());
// System.out.println(nextCh);
Matcher match = pattern.matcher(nextCh + "");
if(match.matches()){
return true;
}
}
return false;
}
public static void main(String[] args) {
String str1 = "{\"reason\":\"成功 \",\"result\":{\"jobid\":\"JH2131171027170837443588J6\",\"realname\":\"林有有\"," +
"\"bankcard\":\"6666430106138888\",\"idcard\":\"130333198901196666\",\"mobile\":\"13288886666\",\"res\":\"1\",\"message\":\"验证成功\"}," +
"\"error_code\":0}";
String str2 = "{\"appkey\":\"E25158BA10104C9180D47FD20CA024B9\",\"idcard\":\"330103197607086666\",\"realname\":\"李有有\",\n" +
"\"applyPhone\":\"18577776667\",\"inviteCode\":\"353753\",\"signature\":\"M2U3Y2M0OTgyZmM1NmUzODAyNjQ0YjNiNGViODBlNTI=\",\n" +
"\"timestamp\":\"1592544985\"}";
boolean b = isNumOrLetter(str1, "130333198901196666");
System.out.println(b);
}
}