您当前的位置:首页 > 互联网百科 > 大数据

聊聊如何自定义数据脱敏

时间:2021-12-28 13:31:55  来源:  作者:linyb极客之路

前言

什么是数据脱敏

数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护

常用脱敏规则

替换、重排、加密、截断、掩码

良好的数据脱敏实施

1、尽可能地为脱敏后的应用,保留脱敏前的有意义信息
2、最大程度地防止黑客进行破解

今天我们聊聊如何自定义数据脱敏

整体思路

本示例通过替换的手段实现脱敏,然后配合常用的框架特性,比如mybatis的拦截器机制或者json的序列化来快速实现脱敏

具体落地

1、定义一个脱敏工具类

可以直接引用hutool工具包,不过它在5.6+版本以上才提供了这个工具

https://www.hutool.cn/docs/#/core/工具类/信息脱敏工具-DesensitizedUtil

不然就自己实现一个,形如下

public class DesensitizedUtils {



	/**
	 * 脱敏,使用默认的脱敏策略
	 * <pre>
	 * DesensitizedUtil.desensitized("100", DesensitizedUtils.DesensitizedType.USER_ID)) =  "0"
	 * DesensitizedUtil.desensitized("段正淳", DesensitizedUtils.DesensitizedType.CHINESE_NAME)) = "段**"
	 * DesensitizedUtil.desensitized("51343620000320711X", DesensitizedUtils.DesensitizedType.ID_CARD)) = "5***************1X"
	 * DesensitizedUtil.desensitized("09157518479", DesensitizedUtils.DesensitizedType.FIXED_PHONE)) = "0915*****79"
	 * DesensitizedUtil.desensitized("18049531999", DesensitizedUtils.DesensitizedType.MOBILE_PHONE)) = "180****1999"
	 * DesensitizedUtil.desensitized("北京市海淀区马连洼街道289号", DesensitizedUtils.DesensitizedType.ADDRESS)) = "北京市海淀区马********"
	 * DesensitizedUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtils.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn"
	 * DesensitizedUtil.desensitized("1234567890", DesensitizedUtils.DesensitizedType.PASSword)) = "**********"
	 * DesensitizedUtil.desensitized("苏D40000", DesensitizedUtils.DesensitizedType.CAR_LICENSE)) = "苏D4***0"
	 * DesensitizedUtil.desensitized("11011111222233333256", DesensitizedUtils.DesensitizedType.BANK_CARD)) = "1101 **** **** **** 3256"
	 * </pre>
	 *
	 * @param str              字符串
	 * @param desensitizedType 脱敏类型;可以脱敏:用户id、中文名、身份证号、座机号、手机号、地址、电子邮件、密码
	 * @return 脱敏之后的字符串
	 * @author dazer and neusoft and qiaomu
	 * @since 5.6.2
	 */
	public static String desensitized(CharSequence str, DesensitizedType desensitizedType) {
		if (StrUtil.isBlank(str)) {
			return StrUtil.EMPTY;
		}
		String newStr = String.valueOf(str);
		switch (desensitizedType) {
			case USER_ID:
				newStr = String.valueOf(DesensitizedUtils.userId());
				break;
			case CHINESE_NAME:
				newStr = DesensitizedUtils.chineseName(String.valueOf(str));
				break;
			case ID_CARD:
				newStr = DesensitizedUtils.idCardNum(String.valueOf(str), 1, 2);
				break;
			case FIXED_PHONE:
				newStr = DesensitizedUtils.fixedPhone(String.valueOf(str));
				break;
			case MOBILE_PHONE:
				newStr = DesensitizedUtils.mobilePhone(String.valueOf(str));
				break;
			case ADDRESS:
				newStr = DesensitizedUtils.address(String.valueOf(str), 8);
				break;
			case EMAIL:
				newStr = DesensitizedUtils.email(String.valueOf(str));
				break;
			case PASSWORD:
				newStr = DesensitizedUtils.password(String.valueOf(str));
				break;
			case CAR_LICENSE:
				newStr = DesensitizedUtils.carLicense(String.valueOf(str));
				break;
			case BANK_CARD:
				newStr = DesensitizedUtils.bankCard(String.valueOf(str));
				break;
			default:
		}
		return newStr;
	}

	/**
	 * 【用户id】不对外提供userId
	 *
	 * @return 脱敏后的主键
	 */
	public static Long userId() {
		return 0L;
	}

	/**
	 * 【中文姓名】只显示第一个汉字,其他隐藏为2个星号,比如:李**
	 *
	 * @param fullName 姓名
	 * @return 脱敏后的姓名
	 */
	public static String chineseName(String fullName) {
		if (StrUtil.isBlank(fullName)) {
			return StrUtil.EMPTY;
		}
		return StrUtil.hide(fullName, 1, fullName.length());
	}

	/**
	 * 【身份证号】前1位 和后2位
	 *
	 * @param idCardNum 身份证
	 * @param front     保留:前面的front位数;从1开始
	 * @param end       保留:后面的end位数;从1开始
	 * @return 脱敏后的身份证
	 */
	public static String idCardNum(String idCardNum, int front, int end) {
		//身份证不能为空
		if (StrUtil.isBlank(idCardNum)) {
			return StrUtil.EMPTY;
		}
		//需要截取的长度不能大于身份证号长度
		if ((front + end) > idCardNum.length()) {
			return StrUtil.EMPTY;
		}
		//需要截取的不能小于0
		if (front < 0 || end < 0) {
			return StrUtil.EMPTY;
		}
		return StrUtil.hide(idCardNum, front, idCardNum.length() - end);
	}

	/**
	 * 【固定电话 前四位,后两位
	 *
	 * @param num 固定电话
	 * @return 脱敏后的固定电话;
	 */
	public static String fixedPhone(String num) {
		if (StrUtil.isBlank(num)) {
			return StrUtil.EMPTY;
		}
		return StrUtil.hide(num, 4, num.length() - 2);
	}

	/**
	 * 【手机号码】前三位,后4位,其他隐藏,比如135****2210
	 *
	 * @param num 移动电话;
	 * @return 脱敏后的移动电话;
	 */
	public static String mobilePhone(String num) {
		if (StrUtil.isBlank(num)) {
			return StrUtil.EMPTY;
		}
		return StrUtil.hide(num, 3, num.length() - 4);
	}

	/**
	 * 【地址】只显示到地区,不显示详细地址,比如:北京市海淀区****
	 *
	 * @param address       家庭住址
	 * @param sensitiveSize 敏感信息长度
	 * @return 脱敏后的家庭地址
	 */
	public static String address(String address, int sensitiveSize) {
		if (StrUtil.isBlank(address)) {
			return StrUtil.EMPTY;
		}
		int length = address.length();
		return StrUtil.hide(address, length - sensitiveSize, length);
	}

	/**
	 * 【电子邮箱】邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示,比如:d**@126.com
	 *
	 * @param email 邮箱
	 * @return 脱敏后的邮箱
	 */
	public static String email(String email) {
		if (StrUtil.isBlank(email)) {
			return StrUtil.EMPTY;
		}
		int index = StrUtil.indexOf(email, '@');
		if (index <= 1) {
			return email;
		}
		return StrUtil.hide(email, 1, index);
	}

	/**
	 * 【密码】密码的全部字符都用*代替,比如:******
	 *
	 * @param password 密码
	 * @return 脱敏后的密码
	 */
	public static String password(String password) {
		if (StrUtil.isBlank(password)) {
			return StrUtil.EMPTY;
		}
		return StrUtil.repeat('*', password.length());
	}

	/**
	 * 【中国车牌】车牌中间用*代替
	 * eg1:null       -》 ""
	 * eg1:""         -》 ""
	 * eg3:苏D40000   -》 苏D4***0
	 * eg4:陕A12345D  -》 陕A1****D
	 * eg5:京A123     -》 京A123     如果是错误的车牌,不处理
	 *
	 * @param carLicense 完整的车牌号
	 * @return 脱敏后的车牌
	 */
	public static String carLicense(String carLicense) {
		if (StrUtil.isBlank(carLicense)) {
			return StrUtil.EMPTY;
		}
		// 普通车牌
		if (carLicense.length() == 7) {
			carLicense = StrUtil.hide(carLicense, 3, 6);
		} else if (carLicense.length() == 8) {
			// 新能源车牌
			carLicense = StrUtil.hide(carLicense, 3, 7);
		}
		return carLicense;
	}

	/**
	 * 银行卡号脱敏
	 * eg: 1101 **** **** **** 3256
	 *
	 * @param bankCardNo 银行卡号
	 * @return 脱敏之后的银行卡号
	 * @since 5.6.3
	 */
	public static String bankCard(String bankCardNo) {
		if (StrUtil.isBlank(bankCardNo)) {
			return bankCardNo;
		}
		bankCardNo = StrUtil.trim(bankCardNo);
		if (bankCardNo.length() < 9) {
			return bankCardNo;
		}

		final int length = bankCardNo.length();
		final int midLength = length - 8;
		final StringBuilder buf = new StringBuilder();

		buf.Append(bankCardNo, 0, 4);
		for (int i = 0; i < midLength; ++i) {
			if (i % 4 == 0) {
				buf.append(CharUtil.SPACE);
			}
			buf.append('*');
		}
		buf.append(CharUtil.SPACE).append(bankCardNo, length - 4, length);
		return buf.toString();
	}
}

其实正常到这个步骤,通过替换实现脱敏就可以完成,可以直接在程序中,直接调用这个工具就行。但是作为一个懂得偷懒的程序员,肯定不满足这样。于是我们会进一步封装

2、自定义脱敏注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Sensitive {

    DesensitizedType strategy() default DesensitizedType.NONE;

    /**
     * 是否使用dfa算法
     * @return
     */
    boolean useDFA() default false;

    /**
     * dfa敏感字符替换,默认替换成 "*"
     * @return
     */
    String dfaReplaceChar() default "*";


    /**
     * dfa敏感字符替换次数
     * @return
     */
    int dfaReplaceCharRepeatCount() default 1;

}

3、利用一些框架特性提升效率

a、如果项目已经有用mybatis,则可以利用mybatis拦截器特性。实现原理就是拦截响应回来的结果,然后对结果进行脱敏处理

@Intercepts(@Signature(type = ResultSetHandler.class,method = "handleResultSets",args = Statement.class))
public class DesensitizedInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        List<Object> list = (List<Object>) invocation.proceed();
        list.forEach(EntityUtils::desensitized);

        return list;
    }

}

b、 如果项目是基于springboot的web项目,则可以利用springboot自带的jackson自定义序列化实现。它的实现原来其实就是在json进行序列化渲染给前端时,进行脱敏。

如果是这种方案,则需对自定义注解进行改造一下,加上

@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizedJsonSerializer.class)

注解。形如下

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizedJsonSerializer.class)
public @interface Sensitive {

    DesensitizedType strategy() default DesensitizedType.NONE;

    /**
     * 是否使用dfa算法
     * @return
     */
    boolean useDFA() default false;

    /**
     * dfa敏感字符替换,默认替换成 "*"
     * @return
     */
    String dfaReplaceChar() default "*";


    /**
     * dfa敏感字符替换次数
     * @return
     */
    int dfaReplaceCharRepeatCount() default 1;

}

序列化脱敏逻辑核心代码如下

public class DesensitizedJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {

    private Sensitive sensitive;
    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(EntityUtils.getDesensitizedValue(sensitive,s));

    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {

        sensitive = beanProperty.getAnnotation(Sensitive.class);

        if(!ObjectUtils.isEmpty(sensitive) && String.class.isAssignableFrom(beanProperty.getType().getRawClass())){
            return this;
        }
        return serializerProvider.findValueSerializer(beanProperty.getType(),beanProperty);
    }
}

示例

以json那种方式为例

1、定义实体对象,需要进行脱敏的属性上加上脱敏注解

@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserDTO {

    private Integer id;

    private String username;

    @Sensitive(strategy = DesensitizedType.PASSWORD)
    private String password;

    @Sensitive(strategy = DesensitizedType.CHINESE_NAME)
    private String fullname;

    @Sensitive(strategy = DesensitizedType.MOBILE_PHONE)
    private String mobile;

    @Sensitive(strategy = DesensitizedType.EMAIL)
    private String email;

    @Sensitive(useDFA = true,dfaReplaceChar = "#",dfaReplaceCharRepeatCount = 3)
    private String remark;
}

2、编写一个测试controller

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;


    @GetMapping(value="/list")
    public AjaxResult listUsers(){
       return AjaxResult.success(userService.listUserDTO());
    }

}

测试结果

聊聊如何自定义数据脱敏

 


如图所示已经进行脱敏

其他方案

1、基于Sharding Sphere实现数据脱敏

具体实现可以参考如下文章

https://jaskey.github.io/blog/2020/03/18/sharding-sphere-data-desensitization/

2、自定义注解格式化

主要实现步骤如下

  • 1、实现AnnotationFormatterFactory接口
  • 2、创建脱敏格式化类实现Formatter
  • 3、将AnnotationFormatterFactory实现的接口注册到FormatterRegistry

具体实现可以参考如下文章

https://blog.csdn.net/qq_27081015/article/details/103295983

4、利用fastjson进行脱敏

主要实现步骤如下

  • 1、实现ValueFilter接口,在process进行脱敏
  • 2、配置fastjson为默认JSON转换
/**
     * 配置fastjson为默认JSON转换
     *
     * @return
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        // 1.定义一个converters转换消息的对象
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        // 2.添加fastjson的配置信息,比如: 是否需要格式化返回的json数据
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        fastJsonConfig.setSerializeFilters(new ValueDesensitizeFilter());//添加自己写的拦截器
        // 3.在converter中添加配置信息
        fastConverter.setFastJsonConfig(fastJsonConfig);
        // 4.将converter赋值给HttpMessageConverter
        HttpMessageConverter<?> converter = fastConverter;
        // 5.返回HttpMessageConverters对象
        return new HttpMessageConverters(converter);
    }

具体实现可以参考如下文章

https://blog.csdn.net/qq_27081015/article/details/103297316

5、利用mybatis-mate

mybatis-plus 企业(数据优雅处理)模块,使用时要配置一下授权码。如下

mybatis-mate:
  cert:
    grant: jinTianYiXueKe
    license: GKXP9r4MCJhGID/DTGigcBcLmZjb1YZGjE4GXaAoxbtGsPC20sxpEtiUr2F7Nb1ANTUekvF6Syo6DzraA4M4oacwoLVTglzfvaEyUogW8L7mydqlsZ4+hlm20kK85eLJK1QsskrSJmreMnEaNh9lsV7Lpbxy9JeGCeM0HPEbRvq8Y+8dUt5bQYLklsa3ZIBexir+4XykZY15uqn1pYIp4pEK0+aINTa57xjJNoWuBIqm7BdFIb4l1TAcPYMTsMXhF5hfMmKD2h391HxWTshJ6jbt4YqdKD167AgeoM+B+DE1jxlLjcpskY+kFs9pIOS7RCcmKBBUOgX2BD/JxhR2gQ==

他的实现机理就是利用json序列化那种,如果感兴趣可以参考如下链接

https://gitee.com/baomidou/mybatis-mate-examples

本文的demo也有基于mybatis-mate实现脱敏,链接如下

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-desensitization/springboot-desensitzation-mybatis-mate

总结

有时候业务场景的实现方式有多种多样,大家要懂得取舍判断,比如上面的方案如果你的项目本来就没用mybatis,但为了脱敏又引入mybatis,这种方案就额外有加入了复杂度,后面维护估计就有得折腾了

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-desensitization



Tags:数据脱敏   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言什么是数据脱敏数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护常用脱敏规则替换、重排、加密、截断、掩码良好的数据脱敏实施1、尽...【详细内容】
2021-12-28  Tags: 数据脱敏  点击:(0)  评论:(0)  加入收藏
▌简易百科推荐
前言什么是数据脱敏数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护常用脱敏规则替换、重排、加密、截断、掩码良好的数据脱敏实施1、尽...【详细内容】
2021-12-28  linyb极客之路    Tags:数据脱敏   点击:(0)  评论:(0)  加入收藏
张欣安科瑞电气股份有限公司 上海嘉定 201801 摘要:随着电力行业各系统接入,海量数据涌现,如何利用电网信息化中大量数据,对客户需求进行判断分析,服务于营销链条,提升企业市场竞...【详细内容】
2021-12-14  安科瑞张欣    Tags:大数据   点击:(10)  评论:(0)  加入收藏
1、什么是数据分析结合分析工具,运用数据分析思维,分析庞杂数据信息,为业务赋能。 2、数据分析师工作的核心流程:(1)界定问题:明确具体问题是什么;●what 发生了什么(是什么)●why 为...【详细内容】
2021-12-01  逆风北极光    Tags:大数据   点击:(26)  评论:(0)  加入收藏
在实际工作中,我们经常需要整理各个业务部门发来的数据。不仅分散,而且数据量大、格式多。单是从不同地方汇总整理这些原始数据就花了大量的时间,更不用说还要把有效的数据收集...【详细内容】
2021-11-30  百数    Tags:数据   点击:(21)  评论:(0)  加入收藏
数据作为新的生产要素,其蕴含的价值日益凸显,而安全问题却愈发突出。密码技术,是实现数据安全最经济、最有效、最可靠的手段,对数据进行加密,并结合有效的密钥保护手段,可在开放环...【详细内容】
2021-11-26  炼石网络    Tags:数据存储   点击:(17)  评论:(0)  加入收藏
导读:网易大数据平台的底层数据查询引擎,选用了Impala作为OLAP查询引擎,不但支撑了网易大数据的交互式查询与自助分析,还为外部客户提供了商业化的产品与服务。今天将为大家分享...【详细内容】
2021-11-26  DataFunTalk    Tags:大数据   点击:(15)  评论:(0)  加入收藏
导读:数据挖掘是一种发现知识的手段。数据挖掘要求数据分析师通过合理的方法,从数据中获取与挖掘项目相关的知识。作者:赵仁乾 田建中 叶本华 常国珍来源:华章科技数据挖掘是一...【详细内容】
2021-11-23  华章科技  今日头条  Tags:数据挖掘   点击:(20)  评论:(0)  加入收藏
今天再给大家分享一个不错的可视化大屏分析平台模板DataColour。 data-colour 可视化分析平台采用前后端分离模式,后端架构设计采用微服务架构模式。 前端技术:Angularjs、Jq...【详细内容】
2021-11-04  web前端进阶    Tags:DashboardClient   点击:(40)  评论:(0)  加入收藏
在Kubernetes已经成了事实上的容器编排标准之下,微服务的部署变得非常容易。但随着微服务规模的扩大,服务治理带来的挑战也会越来越大。在这样的背景下出现了服务可观测性(obs...【详细内容】
2021-11-02  大数据推荐杂谈    Tags:Prometheus   点击:(40)  评论:(0)  加入收藏
同一产品对老客户的要价竟然比新客户要高?这是当下“大数据杀熟”的直接结果。近年来,随着平台经济的蓬勃发展,大数据在为用户服务之外,也引发了多种不合理现象。为了有效遏制“...【详细内容】
2021-10-29    海外网   Tags:大数据   点击:(31)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条