专业建公司网站,采用模版建网站的缺点,接单app平台有哪些,百度关键词挖掘工具大家项目中肯定都会用到日志打印#xff0c;目的是为了以后线上排查问题方便#xff0c;但是有些企业对输出的日志包含的敏感(比如#xff1a;用户身份证号#xff0c;银行卡号#xff0c;手机号等)信息要进行脱敏处理。 哎#xff01;我们最近就遇到了日志脱敏的改造。可… 大家项目中肯定都会用到日志打印目的是为了以后线上排查问题方便但是有些企业对输出的日志包含的敏感(比如用户身份证号银行卡号手机号等)信息要进行脱敏处理。 哎我们最近就遇到了日志脱敏的改造。可以说是一波三折。 浩浩荡荡的日志脱敏改造就这样开始.......... 第一季 在项目中所有log.info方法输出日志的地方手工脱敏很low的一种方法 初期想法很简单就是根据业务判断哪些info输出的地方可能包含敏感信息然后进行手工脱敏。但是有很大弊端一是工作量大二是业务不熟悉很难一次改全。
脱敏工具类
package com.lsl.utills;public class Utils {public static String checkParams(String str){if (str ! null){String strnew str.replaceAll(1[3-9]\\d{9},***);return strnew;}else {return ;}}
}代码中调用这个工具类
package com.lsl.controller;import com.lsl.utills.Utils;
import com.lsl.vo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;Controller
RequestMapping(/lsl)
public class LogbackTestController {private static final Logger LOG LoggerFactory.getLogger(LogbackTestController.class);PostMapping(value qryUser, produces application/json;charsetUTF-8)ResponseBodypublic String qryUser(){User user new User();user.setUserName(LSL);user.setUserPwd(123asd);user.setUserAddr(北京海淀);user.setUserAge(21);user.setUserTel(15803125588);LOG.info(用户信息{},user.toString());LOG.info(脱敏后的用户信息{}, Utils.checkParams(user.toString()));return success;}
}结果截图 这种情况确实也能达到脱敏的目的但是如果代码中有好多info日志输出那么都需要改动工作量太大还容易拉下没有改动的地方。其实我们初期就是这种脱敏反复改了好几次总有遗漏的地方忘记改了。 第二季想研究一种省时省力的方式能不能通过AOP切入log.info方法进行统一脱敏
大概思路就是创建一个切面在调用info方法前把打印内容通过上面的工具类脱敏后在打印。
切面
package com.lsl.config;import com.lsl.utills.Utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;Aspect
public class LogInfoAspect {Pointcut(execution(* org.slf4j.Logger.info(..)))public void loginfoPointcut(){}Before(loginfoPointcut() args(msg))public void bfLogInfo(ProceedingJoinPoint joinPoint,String msg) throws Throwable{System.out.println(切入前参数msg msg);String newStr Utils.checkParams(msg);System.out.println(脱敏处理后参数 newStr);joinPoint.proceed(new Object[]{newStr});}Around(loginfoPointcut() args(msg))public void adLogInfo(ProceedingJoinPoint joinPoint,String msg) throws Throwable{
// String arg (String)joinPoint.getArgs()[0];System.out.println(切入前参数msg msg);String newStr Utils.checkParams(msg);System.out.println(脱敏处理后参数 newStr);joinPoint.proceed(new Object[]{newStr});}
}结果是没法切入到info方法也就无法脱敏了
如下图 原因也很简单AOP是交付spring托管的bean才能使用动态代理实现切入进行操作。然后logback并没有由spring托管所以不行。
我后来想到在配置类里交付spring托管不就行了但是也不行大家猜猜是什么原因呢 第三季利用logback脱敏并实现异步写入日志文件
大概思路是需要自己写脱敏转换器然后引入logback.xml中异步写入文件比较方便网上好多资料大家可以自行查询。
脱敏转换器
package com.lsl.config;import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.apache.commons.lang3.StringUtils;import java.util.regex.Matcher;
import java.util.regex.Pattern;public class SensitiveConverter extends MessageConverter {//手机号正则private static final String PHONE_REG (1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}|[96]\\d{7}|6[68]\\d{5}|09\\d{8})([^^\\d]|$);//身份证号正则private static final String IDCARD_REG ;//脱敏字符private static final String SECRET ***************;//要脱敏的类型private static String sensitiveType;public static void setSensitiveType(String sensitiveType){SensitiveConverter.sensitiveType sensitiveType;}Overridepublic String convert(ILoggingEvent event){String requestLogMsg event.getFormattedMessage();return filtrSensitive(requestLogMsg,sensitiveType);}public String filtrSensitive(String content,String sensitiveType){try {if (StringUtils.isBlank(content)){return content;}//手机号脱敏if (sensitiveType.contains(phone)){content filterPhone(content);}//身份证脱敏if (sensitiveType.contains(idcard)){}return content;} catch (Exception e) {return content;}}private static String filterPhone(String num){Pattern pattern Pattern.compile(PHONE_REG);Matcher matcher pattern.matcher(num);StringBuffer sb new StringBuffer();while (matcher.find()){String matchResult matcher.group();if (!StringUtils.isNumeric(matchResult.substring(matchResult.length() - 1))){//大陆手机号if (matchResult.startsWith(1)){matcher.appendReplacement(sb,baseSensitive(matchResult,3,5));}//港澳手机号if (matchResult.startsWith(6) || matchResult.startsWith(9)){}}else {//大陆手机号if (matchResult.startsWith(1)){matcher.appendReplacement(sb,baseSensitive(matchResult,3,4));}//港澳手机号if (matchResult.startsWith(6) || matchResult.startsWith(9)){}}}matcher.appendTail(sb);return sb.toString();}private static String baseSensitive(String str,int startlen,int endlen){if (StringUtils.isBlank(str)){return ;}StringBuffer sb new StringBuffer();sb.append(SECRET);return StringUtils.left(str,startlen).concat(StringUtils.leftPad(StringUtils.right(str,endlen),str.length()- startlen,sb.toString()));}}package com.lsl.config;import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;Component
public class SensitiveConverterProperties implements InitializingBean {Value(${logging.sensitive.type})private String sensitiveType;Overridepublic void afterPropertiesSet() throws Exception {SensitiveConverter.setSensitiveType(this.sensitiveType);}public String getSensitiveType() {return sensitiveType;}public void setSensitiveType(String sensitiveType) {this.sensitiveType sensitiveType;}
}application.properties文件 server.port8080logging.sensitive.typephonelogback.xml
?xml version1.0 encodingUTF-8?
configuration debugfalse!-- 转换配置 必选配置--conversionRule conversionWordsensitiveMsg converterClasscom.lsl.config.SensitiveConverter /conversionRule!-- 控制台输出 --appender nameCONSOLE classch.qos.logback.core.ConsoleAppenderencoderpattern%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %sensitiveMsg%n/pattern/encoder/appender!-- 按照每天生成日志文件 --appender nameROLLING classch.qos.logback.core.rolling.RollingFileAppenderfilelogs/app.log/filerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePatternlogs/app.%d{yyyy-MM-dd}.log/fileNamePatternmaxHistory30/maxHistory/rollingPolicyencoderpattern%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %sensitiveMsg%n/pattern/encoder/appender!-- 异步日志配置 --appender nameASYNC_FILE classch.qos.logback.classic.AsyncAppenderappender-ref refROLLING //appender!-- 项目包下所有info日志输出到控制台 --logger namecom.lsl levelINFO additivityfalseappender-ref refCONSOLE //logger!-- 项目包下所有info日志异步输出到文件 --logger namecom.lsl levelINFO additivityfalseappender-ref refASYNC_FILE //logger!-- Root Logger --root levelINFOappender-ref refCONSOLE /appender-ref refROLLING //root
/configurationcontrooler验证
package com.lsl.controller;import com.lsl.vo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;Controller
RequestMapping(/lsl)
public class LogbackTestController {private static final Logger LOG LoggerFactory.getLogger(LogbackTestController.class);PostMapping(value qryUser, produces application/json;charsetUTF-8)ResponseBodypublic String qryUser(){User user new User();user.setUserName(LSL);user.setUserPwd(123asd);user.setUserAddr(北京海淀);user.setUserAge(21);user.setUserTel(15803125588);LOG.info(用户信息{},user.toString());return success;}
}验证截图 总结
利用logback的脱敏转换器是非常方便且灵活的。自己可以定义各种业务敏感信息的脱敏策略我这里面只写了手机号的脱敏策略。而且在配置文件properties中可以配置对那些敏感信息进行脱敏。
比如logging.sensitive.typephone,idcard
这样就是手机号和身份证号同时进行脱敏只是具体的身份证号的脱敏规则我以后在补上吧。