logback日志之脱敏处理

  对于项目日志脱敏,大家肯定都不陌生,现在对于信息安全越来越重视,在日志中直接打印手机号,身份证号等私人信息和容易造成个人信息的泄露,所以几乎所有的公司都会要求日志中敏感信息的处理,本人也是因为公司安全部门检查,因为部分日志输出了敏感信息,需要对项目日志进行改造,但是问题是如果我们挨个去排查那个日志有输出敏感信息的话,那工作量无疑是巨大的,那有没有一种方式进行全局处理呢,答案是肯定的,因为公司使用的slf4j+logback,就以此为例给出解决方案。因为只是个小技术工具,所以直接上代码:

logback.xml配置文件修改

<springProperty scope="context" name="log.consolePattern" source="hcf.log.console-pattern" 
defaultValue="%red(%d{yyyy-MM-dd HH:mm:ss.SSS})|%highlight(%level)|%green(%thread)|%X{clientIp}|%X{traceId}|%X{rpcId}|%boldMagenta(%c.%M[%L])|%cyan(%msg%n)"/>
<conversionRule conversionWord="msg" converterClass="com.credithc.channel.common.util.SensitiveConverter"> </conversionRule>

注意:

  1. conversionRule标签必须紧挨着configuration标签写,绝对不可以放在appender标签下面,但是可以放在springProperty下面

  2. conversionRule标签中的converterClass属性指向的是我们自定义的处理敏感信息的类,conversionWord的值对应的是我们定义的日志格式中的日志内容的占位符,也就是上面代码中%msg去掉%的部分

自定义脱敏处理类

 

package com.credithc.openapi.flowplatform.util;

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;

/**
 * 日志脱敏过滤器
 *
 * @author 邝翔
 */
public class SensitiveConverterUtil extends MessageConverter {

    private static final String PHONE_REGEX = "(\\+861[3|4|5|7|8][0-9]\\d{8}[^\\d])|(^1[3|4|5|7|8][0-9]\\d{8})[^\\d]|([^\\d]1[3|4|5|7|8][0-9]\\d{8}[^\\d])";
    private static final String IDCARD_REGEX = "[^\\d]([1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx])[^\\d]|[^\\d](^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3})[^\\d]";
    private static final String KEY = "axedfqLGpu";

    @Override
    public String convert(ILoggingEvent event) {
        // 获取原始日志
        String requestLogMsg = event.getFormattedMessage();
        // 获取返回脱敏后的日志
        return filterSensitive(requestLogMsg);
    }

    /**
     * 对敏感信息脱敏
     */
    private static String filterSensitive(String content) {
        try {
            if (StringUtils.isBlank(content)) {
                return content;
            }
            content = filterIdcard(content);
            content = filterMobile(content);
            return content;
        } catch (Exception e) {
            return content;
        }
    }

    /**
     * 身份证号脱敏
     */
    private static String filterIdcard(String num) {
        Pattern pattern = Pattern.compile(IDCARD_REGEX);
        Matcher matcher = pattern.matcher(num);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, baseSensitive(matcher.group(), 4, 4));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 手机号码脱敏
     */
    private static String filterMobile(String num) {
        Pattern pattern = Pattern.compile(PHONE_REGEX);
        Matcher matcher = pattern.matcher(num);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, baseSensitive(matcher.group(), 3, 4));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 基础脱敏处理 指定起止展示长度 剩余用"KEY"中字符替换
     *
     * @param str         待脱敏的字符串
     * @param startLength 开始展示长度
     * @param endLength   末尾展示长度
     * @return 脱敏后的字符串
     */
    private static String baseSensitive(String str, int startLength, int endLength) {
        if (StringUtils.isBlank(str)) {
            return "";
        }
        String replacement = str.substring(startLength, str.length() - endLength);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < replacement.length(); i++) {
            char ch;
            if (replacement.charAt(i) >= '0' && replacement.charAt(i) <= '9') {
                ch = KEY.charAt(replacement.charAt(i) - '0');
            } else {
                ch = replacement.charAt(i);
            }
            sb.append(ch);
        }
        return StringUtils.left(str, startLength).concat(StringUtils.leftPad(StringUtils.right(str, endLength), str.length() - startLength, sb.toString()));
    }

    /**
     * 按"KEY"中字符解密
     */
    private static String decrypt(String str, int startLength, int endLength) {
        if (StringUtils.isBlank(str)) {
            return "";
        }
        String replacement = str.substring(startLength, str.length() - endLength);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < replacement.length(); i++) {
            int index = KEY.indexOf(replacement.charAt(i));
            if (index != -1) {
                sb.append(index);
            } else {
                sb.append(replacement.charAt(i));
            }
        }
        return StringUtils.left(str, startLength).concat(StringUtils.leftPad(StringUtils.right(str, endLength), str.length() - startLength, sb.toString()));
    }
}

 

posted @ 2019-12-25 11:12  海棠--依旧  Views(12946)  Comments(0Edit  收藏  举报