logback日志实现 敏感数据脱敏

在logback.xml 中  添加  

  <conversionRule conversionWord="msg" converterClass="com.common.utils.SensitiveDataConverter"> </conversionRule>

 

import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 敏感信息脱敏处理
 * @author AAA
 */
public class SensitiveDataConverter extends MessageConverter {


    /**
     * 日志脱敏开关
     */
    private static String converterCanRun = "true";
    /**
     * 日志脱敏关键字
     */
    private static String sensitiveDataKeys = "idCard,dTel,dMobile,dAddress,jMobile,jAddress,address,phone";

    private static Pattern pattern = Pattern.compile("[0-9a-zA-Z]");

    //手机号正则匹配
    private static final String PHONE_REGEX = "1[3|4|5|6|7|8|9][0-9]\\d{8}";
    //身份证号正则匹配
    private static final String IDCARD_REGEX = "([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])|(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3})";

    //之所以定义这个参数,完全是处于公司的要求,因为公司要求敏感信息在日志输出时被脱敏后,还能按照一定的规则还原,所以就用这些字母来进行处理了,对于没有这种要求的,就更简单了,直接用*去脱敏就可以了,大家很容易根据现在的代码进行改造,这里不在多讲
    private static final String KEY = "axedfqLGpu";

    @Override
    public String convert(ILoggingEvent event){
        // 获取原始日志
        String oriLogMsg = event.getFormattedMessage();

        // 获取脱敏后的日志
        String afterLogMsg = invokeMsg(oriLogMsg);

       //  return  afterLogMsg;
        return filterSensitive(afterLogMsg);

    }
    /**
     * 处理日志字符串,返回脱敏后的字符串
     * @param: msg
     * @return
     */
    public static String invokeMsg(final String oriMsg){
        String tempMsg = oriMsg;
        if("true".equals(converterCanRun)){
            // 处理字符串
            if(sensitiveDataKeys != null && sensitiveDataKeys.length() > 0){
                String[] keysArray = sensitiveDataKeys.split(",");
                for(String key: keysArray){
                    int index= -1;
                    do{
                        index = tempMsg.indexOf(key, index+1);
                        if(index != -1){
                            // 判断key是否为单词字符
                            if(isWordChar(tempMsg, key, index)){
                                continue;
                            }
                            // 寻找值的开始位置
                            int valueStart = getValueStartIndex(tempMsg, index + key.length());

                            // 查找值的结束位置(逗号,分号)........................
                            int valueEnd = getValuEndEIndex(tempMsg, valueStart);

                            // 对获取的值进行脱敏
                            String subStr = tempMsg.substring(valueStart, valueEnd);
                            subStr = tuomin(subStr, key);
                            ///
                            tempMsg = tempMsg.substring(0,valueStart) + subStr + tempMsg.substring(valueEnd);
                        }
                    }while(index != -1);
                }
            }
        }
        return tempMsg;
    }

    /**
     * 判断从字符串msg获取的key值是否为单词
     * index为key在msg中的索引值
     * @return
     */
    private static boolean isWordChar(String msg, String key, int index){
        // 必须确定key是一个单词............................
        if(index != 0){ // 判断key前面一个字符
            char preCh = msg.charAt(index-1);
            Matcher match = pattern.matcher(preCh + "");
            if(match.matches()){
                return true;
            }
        }
        // 判断key后面一个字符
        char nextCh = msg.charAt(index + key.length());
        Matcher match = pattern.matcher(nextCh + "");
        if(match.matches()){
            return true;
        }
        return false;
    }

    /**
     * 获取value值的开始位置
     * @param msg 要查找的字符串
     * @param valueStart 查找的开始位置
     * @return
     */
    private static int getValueStartIndex(String msg, int valueStart ){
        // 寻找值的开始位置.................................
        do{
            char ch = msg.charAt(valueStart);
            if(ch == ':' || ch == '='){ // key与 value的分隔符
                valueStart ++;
                ch = msg.charAt(valueStart);
                if(ch == '"'){
                    valueStart ++;
                }
                break;    // 找到值的开始位置
            }else{
                valueStart ++;
            }
        }while(true);
        return valueStart;
    }

    /**
     * 获取value值的结束位置
     * @return
     */
    private static int getValuEndEIndex(String msg,int valueEnd){
        do{
            if(valueEnd == msg.length()){
                break;
            }
            char ch = msg.charAt(valueEnd);

            if(ch == '"'){ // 引号时,判断下一个值是结束,分号还是逗号决定是否为值的结束
                if(valueEnd+1 == msg.length()){
                    break;
                }
                char nextCh = msg.charAt(valueEnd+1);
                if(nextCh ==';' || nextCh == ','){
                    // 去掉前面的 \  处理这种形式的数据
                    while(valueEnd>0 ){
                        char preCh = msg.charAt(valueEnd-1);
                        if(preCh != '\\'){
                            break;
                        }
                        valueEnd--;
                    }
                    break;
                }else{
                    valueEnd ++;
                }
            }else if (ch ==';' || ch == ',' || ch == '}'){
                break;
            }else{
                valueEnd ++;
            }

        }while(true);
        return valueEnd;
    }

    /**
     *  调用脱敏工具类进行字段日志处理
     * @param submsg
     * @param key
     * @return
     */
    private static String tuomin(String submsg, String key){
        // idcard:身份证号, realname:姓名, bankcard:银行卡号, mobile:手机号,attribute10,shipAddress,detailedAddr:地址
        if(Lists.newArrayList("idCard","id_card").contains(key)){
            return SensitiveInfoUtils.idCardNum(submsg);
        }
//        if(Lists.newArrayList("realname","customerName").equals(key)){
//            return SensitiveInfoUtils.chineseName(submsg);
//        }
        if(Lists.newArrayList("dTel","","dMobile","","jMobile","","phone").contains(key)){
            return SensitiveInfoUtils.mobilePhone(submsg);
        }
        if(Lists.newArrayList("dAddress","","jAddress","","address").contains(key)){
            return SensitiveInfoUtils.address(submsg,3);
        }
        return "";
    }





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

    /**
     * 对敏感信息脱敏
     * @param content
     * @return
     * @author ljh
     * @date 2019年12月17日
     */
    public static String filterSensitive(String content) {
        try {
            if(StringUtils.isBlank(content)) {
                return content;
            }
            content = filterIdcard(content);
            return filterMobile(content);
        }catch(Exception e) {
            return content;
        }
    }

    /**
     * [身份证号] 指定展示几位,其他隐藏 。<例子:1101**********5762>
     * @param num
     * @return
     * @author ljh
     * @date 2019年12月18日
     */
    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();
    }

    /**
     * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>
     * @param num
     * @return
     * @author ljh
     * @date 2019年12月18日
     */
    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);
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<replacement.length();i++) {
            char ch;
            if(replacement.charAt(i)>='0' && replacement.charAt(i)<='9') {
                ch = KEY.charAt((int)(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"中字符解密
     * @param str
     * @param startLength
     * @param endLength
     * @return
     * @author ljh
     * @date 2019年12月18日
     */
    private static String decrypt(String str, int startLength, int endLength) {
        if (StringUtils.isBlank(str)) {
            return "";
        }
        String replacement = str.substring(startLength,str.length()-endLength);
        StringBuffer sb = new StringBuffer();
        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()));
    }

    public static void main(String[] args) {
        String tempMsg = "{sign=f88898b2677e62f1ad54b9e330c0a27e, idCard=130333198901192762, realname=%E5%BE%90%E5%BD%A6%E5%A8%9C, key=c5d34d4c3c71cc45c88f32b4f13da887, mobile=13210141605, bankcard=6226430106137525}";
        String tempMsg1 = "{\"reason\":\"成功 \",\"result\":{\"jobid\":\"JH2131171027170837443588J6\",\"realname\":\"李哪娜\",\"bankcard\":\"6226430106137525\",\"idcard\":\"130333198901192762\",\"mobile\":\"13210141605\",\"res\":\"1\",\"message\":\"验证成功\"},\"error_code\":0}";
        String shipAddress ="{shipAddress=宁夏回族自治区.银川市.金凤区.长城中路街道收货人:+卜广龙手机号码:+13992283627}";
        String detailedAddr ="{\"attribute10\":\"浙江省.杭州市.桐庐县.桐君街道.收货人: 陈静手机号码: 15168393010所在地区: 浙江省杭州市桐庐县城南街道详细地址: 白云源路1618号银通汽车4楼\"}";
        SensitiveDataConverter sc = new SensitiveDataConverter();
        System.out.println(sc.invokeMsg(tempMsg));
        System.out.println(sc.invokeMsg(tempMsg1));
        System.out.println(sc.invokeMsg(shipAddress));
        System.out.println(sc.invokeMsg(detailedAddr));

    }

}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值