工具类篇【四】日志脱敏

工具类篇大全

工具类篇【一】String字符串

工具类篇【二】BigDecimal计算

工具类篇【三】日期Date转换

工具类篇【四】日志脱敏

工具类篇【五】Random随机生成字符串

工具类篇【六】克隆对象的2种常用方法


 

前言

随着科技和信息化时代的加速发展,尤其在5G和大数据时代的今天,信息安全也逐渐成为人民更为关注的事情。为用户和会员保护个人隐私信息显得尤为重要。对于一些敏感数据的展示和存储,公司安全部门经常要求加密或脱敏处理。对敏感数据进行MD5加密存储,前端和日志脱敏处理。如:身份证、手机号、姓名、地址等,尤其是对敏感数据安全性要求较高行业和公司;电商、通信、金融等行业。

一、logback工具包

今天主要讲述后台系统对于敏感数据进行日志脱敏处理,拿来即用的工具实现类。利用logback工具包的日志脱敏处理,非常简单和方便。主要分为以下几个步骤:

  • 定义脱敏日志关键字
  • 获取关键字开始索引位置
  • 获取关键字结束索引位置
  • 进行关键字脱敏处理

日志脱敏处理主工具类:

package **.util;

import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.google.common.collect.Lists;

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

/**
 * @Author: **
 * @Date: 2020/9/17 10:18
 * @param: 数据脱敏处理转换类【logback包】
 * @return:
 */
public class SensitiveDataConverter extends MessageConverter {

    /**
     * 日志脱敏开关
     */
    private static String converterCanRun = "true";
    /**
     * 日志脱敏关键字
     */
    private static String sensitiveDataKeys = "idcard,realname,bankcard,mobile,shipAddress,detailedAddr,customerName,shipAddriess";

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

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

        // 获取脱敏后的日志
        String afterLogMsg = invokeMsg(oriLogMsg);
        return 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("idcard".equals(key)){
            return SensitiveInfoUtils.idCardNum(submsg);
        }
        if(Lists.newArrayList("realname","customerName").equals(key)){
            return SensitiveInfoUtils.chineseName(submsg);
        }
        if("bankcard".equals(key)){
            return SensitiveInfoUtils.bankCard(submsg);
        }
        if("mobile".equals(key)){
            return SensitiveInfoUtils.mobilePhone(submsg);
        }
        if(Lists.newArrayList("attribute10","shipAddress","detailedAddr","shipAddriess").contains(key)){
            return SensitiveInfoUtils.address(submsg);
        }
        return "";
    }

    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));
    }
}

二、关键字处理工具类

针对需要脱敏的关键字进行逐个个性化处理,也可定义方法动态传入关键字进行脱敏处理:

package com.vip.fcs.app.ar.util;

import org.apache.commons.lang3.StringUtils;

/**
 * @Author: **
 * @Date: 2020/9/17 10:23
 * @param: 数据脱敏处理工具类
 * @return:
 */
public class SensitiveInfoUtils {

    /**
     * [姓名] 只显示第一个汉字,其他隐藏为星号<例子:李**>
     *
     * @param fullName
     * @return
     */
    public static String chineseName(String fullName) {
        if (StringUtils.isBlank(fullName)) {
            return "";
        }
        String name = StringUtils.left(fullName, 1);
        return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
    }

    /**
     * [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762>
     *
     * @param idCardNum
     * @return
     */
    public static String idCardNum(String idCardNum) {
        if (StringUtils.isBlank(idCardNum)) {
            return "";
        }
        String num = StringUtils.right(idCardNum, 4);
        return StringUtils.leftPad(num, StringUtils.length(idCardNum), "*");
    }

    /**
     * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>
     *
     * @param num
     * @return
     */
    public static String mobilePhone(String num) {
        if (StringUtils.isBlank(num)) {
            return "";
        }
        return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 4),StringUtils.length(num), "*"), "***"));
    }

    /**
     * [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>
     *
     * @param cardNum
     * @return
     */
    public static String bankCard(String cardNum) {
        if (StringUtils.isBlank(cardNum)) {
            return "";
        }
        return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), "******"));
    }

    /**
     * [会员地址] 前六位,其他用星号隐藏每位1个星号<例子:广东省广州市*******>
     *
     * @param:cardNum
     * @return
     */
    public static String address(String address) {
        if (StringUtils.isBlank(address) || address.length() <9) {
            return "";
        }
        String name = StringUtils.left(address, 9);
        return StringUtils.rightPad(name, StringUtils.length(address), "*********");
    }

}

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序大视界

原创不易,请给点支持和鼓励吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值