项目中使用到了logback. 过滤不打印base64字符

新建日志处理类

/**
 * logback, 替换日志中的base64编码
 */
public class Base64ReplaceLogbackLayout extends PatternLayout {
    private static final Pattern IMAGE_BASE64_PATTERN = Pattern.compile("[A-Za-z\\d+/]{214}([A-Za-z\\d+/][A-Za-z\\d+/=]+|==)");

    @Override
    public String doLayout(ILoggingEvent event) {
        String msg = super.doLayout(event);
        // 替换图片 base64
        Matcher imageBase64Matcher = IMAGE_BASE64_PATTERN.matcher(msg);
        if(imageBase64Matcher.find()){
            return imageBase64Matcher.replaceAll("[IMAGE BASE64]");
        } else {
            return msg;
        }
    }
}

在logback中使用

<appender name="LOG-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/log.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_DIR}/log.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
            <maxFileSize>500MB</maxFileSize>
            <totalSizeCap>30GB</totalSizeCap>
            <maxHistory>10</maxHistory>
        </rollingPolicy>

        <layout class="boot.draco.autoconfig.log.Base64ReplaceLogbackLayout">
            <pattern>${logPattern}</pattern>
        </layout>
        <encoder>
            <pattern>${logPattern}</pattern>
            <charset>UTF-8</charset>
        </encoder>
</appender>

在普通的类中使用

ublic class Base64Util {
    public static final String base64Pattern = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
    private static final Pattern IMAGE_BASE64_PATTERN = Pattern.compile("[A-Za-z\\d+/]{214}([A-Za-z\\d+/][A-Za-z\\d+/=]+|==)");
    /**
     * 判断是否是base64字符
     */
    public static boolean isBase64(String str) {
        return Pattern.matches(base64Pattern, str);
    }

    public static String replaceBase64(String str){
        if(null == str || str.isEmpty()){
            return str;
        }
        Matcher imageBase64Matcher = IMAGE_BASE64_PATTERN.matcher(str);
        if(imageBase64Matcher.find()){
            return imageBase64Matcher.replaceAll("[IMAGE BASE64]");
        } else {
            return str;
        }
    }
    
}

处理日志中的敏感字符

/**
 * 重写log4j的PatternLayout,实现日志信息中敏感信息的编码或加密
 */
@Slf4j
public class Log4jEncodeLayout extends PatternLayout {

    /** 要匹配的正则表达式(身份证/银行卡) */
    private Pattern patternChar;
    /** 要匹配的正则表达式(姓名) */
    private Pattern namepatternChar;
    private int keys_length_char;// 要匹配关键字的数目
    private String[] charKeys;
    private static final String LOG4J_CHAR_KEYS="identityCode,cardId";
    
    private void init(){
        String str_char_keys = StringUtils.trim(LOG4J_CHAR_KEYS);
        log.info("str_char_keys :{}",str_char_keys);
        if(!StringUtils.isEmpty(str_char_keys)){//没有配置log4j.char.keys,不需要替换*
            charKeys = str_char_keys.split(",");// 读取配置中要加密的key
            
            // 组织正则表达式
            StringBuffer sbRegChar = new StringBuffer();
            sbRegChar.append("(");
            for (int i = 0; i < charKeys.length; i++) {
                sbRegChar.append("(");
                sbRegChar.append(charKeys[i]);
                sbRegChar.append(")");
                if (i < charKeys.length - 1) {
                    sbRegChar.append("|");
                }
            }
            StringBuffer namesbRegChar = new StringBuffer(sbRegChar);
            namesbRegChar.append(")(=|:|:)([\u4E00-\u9FA5\u00B7]{1,16})(;|,|\\||\\}|]|$)");
            //由于(\\s*\\w+={0,2})  key:value  中value中结尾包括==(base64导致,所以修改该写法)
            sbRegChar.append(")(=|:|:)(\\s*\\w+={0,2})(;|,|\\||\\}|]|$)");
            
            namepatternChar = Pattern.compile(namesbRegChar.toString());// 编译正则表达式
            patternChar = Pattern.compile(sbRegChar.toString());// 编译正则表达式
            keys_length_char = charKeys.length;
        }
        
    }
    public Log4jEncodeLayout(){
        super();
        init();
    }

    
    @Override
    public String doLayout(ILoggingEvent event) {
        String msg = super.doLayout(event);
        return dimChar(msg); //对日志关键信息模糊配置* 如果没配置返回正常信息
    }
    
    /**
     * 对银行卡以及身份证号脱敏处理
     * 1.判断配置文件中是否已经配置需要脱敏字段
     * 2.判断内容是否有需要脱敏的敏感信息
     *     2.1 没有需要脱敏信息直接返回
     * 3.判断敏感信息内容是否需要处理
     *     3.1 处理银行卡和身份证敏感信息
     *     3.2 处理用户姓名敏感信息
     * @param @param msg
     * @param @return
     * @return String 
     * @throws
     */
    private String dimChar(String msg) {
        try{
            //1.判断配置文件中是否已经配置需要脱敏字段
            if(keys_length_char <= 0 || patternChar == null) {
                return msg;
            }
            
            //2.判断内容是否有需要脱敏的敏感信息
            boolean flag=false;
            for (String key : charKeys) {
                if(msg.contains(key)){
                    flag=true;
                    break;
                }
            }
            
            //2.1 没有需要脱敏信息直接返回
            if(!flag) {
                return msg;
            }
            
            Matcher match = patternChar.matcher(msg);
            boolean nameFlag = false;
            // 处理要打印的日志信息
            //3.判断敏感信息内容是否需要处理
            StringBuffer sbMsg = new StringBuffer();
            while (match.find()) {
                //3.1 处理银行卡和身份证敏感信息
                nameFlag = true;
                // group(1)匹配key,group(keys_length+2)匹配(=|:|:),group(keys_length+3)匹配value,group(keys_length+4)匹配(;|,|\\||]|\\)|$)
                match.appendReplacement(
                        sbMsg,
                        match.group(1)
                                + match.group(keys_length_char + 2)
                                + replaceChar(match.group(keys_length_char + 3))
                                + match.group(keys_length_char + 4));
            }
            match.appendTail(sbMsg);// 增加最后一个匹配项后面的值
            //3.2 处理用户姓名敏感信息
            if(nameFlag) {
                match = namepatternChar.matcher(sbMsg);
                sbMsg = new StringBuffer();
            }else{
                match = namepatternChar.matcher(msg);
            }
            while (match.find()) {
                nameFlag = true;
                // group(1)匹配key,group(keys_length+2)匹配(=|:|:),group(keys_length+3)匹配value,group(keys_length+4)匹配(;|,|\\||]|\\)|$)
                match.appendReplacement(
                        sbMsg,
                        match.group(1)
                                + match.group(keys_length_char + 2)
                                + replaceNameChar(match.group(keys_length_char + 3))
                                + match.group(keys_length_char + 4));
            }

            match.appendTail(sbMsg);// 增加最后一个匹配项后面的值
            return sbMsg.toString()+"\n";
        }catch (Exception e) {
            //如果跑出异常为了不影响流程,直接返回原信息
            return msg;
        }
    }
    
    
    /**
     * 日志关键字用* 替换
     * 规则:  value <= 6     替换为******
     *        6 > value <= 12  后四位保留,其他为*
     *        value > 12      前6位保留  中间*  后4位保留    
     * @param value
     * @return 
     */
    private static String replaceChar(String value){

        if(StringUtils.isEmpty(value)){
            return "";
        }
        if(value.length() <= 6){ // value <= 6   替换为******
            return lStr("",'*',value.length());
        }else if(value.length() > 6 && value.length() <= 12){ //后四位保留,其他为*
            int valLen = value.length();
            String replaceHeadStr = value.substring(value.length() -4);
            return replaceHeadStr = lStr(replaceHeadStr,'*',valLen);
        }else if(value.length() > 12){ //前6位保留  中间*  后4位保留 
            String replaceHeadStr = value.substring(0,6);
            String replaceTailStr = value.substring(value.length()-4);
            String dimStr = lStr("",'*',value.length()-10);
            return replaceHeadStr+dimStr+ replaceTailStr;
        }else{
            return value;
        }
    }
    
    /**
     * 日志姓名关键字替换
     * 保留第一个汉字,后边用*号表示(例如:张三--》张*)
     * @param @param value
     * @param @return
     * @return String 
     * @throws
     */
    private static String replaceNameChar(String value){

        if(StringUtils.isEmpty(value)){
            return "";
        }
        String replaceHeadStr = value.substring(0,1);
        return replaceHeadStr + lStr("",'*',value.length() - 1);
    }
    
    /*
     * 左补长char
     */
    public static String lStr(String s, char ch, int width) {
        if (s.length() < width) { // 需要前面补'0'
            while (s.length() < width)
                s = ch + s;
        } else { // 需要将高位丢弃
            s = s.substring(s.length() - width, s.length());
        }
        return s;
    }
}

文章作者: 刘同学
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 刘同学的小站
后端 Java
喜欢就支持一下吧