数据脱敏处理

news2024/11/15 12:50:23

有关于数据脱敏处理,小编也是在文章上面看到的,感觉很有意思,那么,便深入研究了一下,首先我们先来看一下数据脱敏之后的结果吧?

用结果说话更能深入人心!!

下面是数据库中的字段:请看Phone属性!数据库中存储的就是用户直接输入的数据

但是,当我们对该phone字段脱敏处理以后,在前台我们看到的数据是:

这就能够有效的避免一些不必要的信息外泄!比如:银行卡?身份证号?地址?手机号码?等涉及到个人隐私信息!!真的很有用呢!!

那么,我们便来看一下实际的代码吧!!

首先添加依赖包

默认的情况下,如果当前项目已经添加了spring-web包或者spring-boot-starter-web包,因为这些jar包已经集成了jackson相关包,因此无需重复依赖。

如果当前项目没有jackson包,可以通过如下方式进行添加相关依赖包

     <!-- Jackson Databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.1</version>
        </dependency>


        <!-- Apache Commons Lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

编写脱敏类型枚举类,满足不同场景的处理

package com.example.desensitization;

public enum SensitiveEnum {

    /**
     * 中文名
     */
    CHINESE_NAME,

    /**
     * 身份证号
     */
    ID_CARD,

    /**
     * 座机号
     */
    FIXED_PHONE,

    /**
     * 手机号
     */
    MOBILE_PHONE,

    /**
     * 地址
     */
    ADDRESS,

    /**
     * 电子邮件
     */
    EMAIL,

    /**
     * 银行卡
     */
    BANK_CARD,

    /**
     * 公司开户银行联号
     */
    CNAPS_CODE
}

编写脱敏注解类

package com.example.desensitization;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerialize.class)
public @interface SensitiveWrapped {

    /**
     * 脱敏类型
     * @return
     */
    SensitiveEnum value();
}

编写脱敏序列化类

package com.example.desensitization;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import java.io.IOException;
import java.util.Objects;

/**
 * 用于序列化字符串的脱敏处理类
 * 继承自JsonSerializer<String>,同时实现ContextualSerializer接口
 * 该类根据敏感信息类型对字符串进行脱敏处理
 */
public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer {

    /**
     * 脱敏类型
     */
    private SensitiveEnum type;


    /**
     * 根据脱敏类型对字符串进行脱敏处理
     *
     * @param s 输入的字符串
     * @param jsonGenerator 用于写入处理后的字符串的Json生成器
     * @param serializerProvider 序列化提供者
     * @throws IOException 如果写入操作导致IO错误
     */
    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        // 根据不同的敏感信息类型,调用相应的方法对敏感信息进行处理,并写入JSON
        switch (this.type) {
            case CHINESE_NAME: {
                // 处理并写入中文姓名敏感信息
                jsonGenerator.writeString(SensitiveInfoUtils.chineseName(s));
                break;
            }
            case ID_CARD: {
                // 处理并写入身份证号码敏感信息
                jsonGenerator.writeString(SensitiveInfoUtils.idCardNum(s));
                break;
            }
            case FIXED_PHONE: {
                // 处理并写入固定电话敏感信息
                jsonGenerator.writeString(SensitiveInfoUtils.fixedPhone(s));
                break;
            }
            case MOBILE_PHONE: {
                // 处理并写入移动电话敏感信息
                jsonGenerator.writeString(SensitiveInfoUtils.mobilePhone(s));
                break;
            }
            case ADDRESS: {
                // 处理并写入地址敏感信息,精度为4级
                jsonGenerator.writeString(SensitiveInfoUtils.address(s, 4));
                break;
            }
            case EMAIL: {
                // 处理并写入电子邮件敏感信息
                jsonGenerator.writeString(SensitiveInfoUtils.email(s));
                break;
            }
            case BANK_CARD: {
                // 处理并写入银行账户敏感信息
                jsonGenerator.writeString(SensitiveInfoUtils.bankCard(s));
                break;
            }
            case CNAPS_CODE: {
                // 处理并写入银行间清算系统(CNAPS)代码敏感信息
                jsonGenerator.writeString(SensitiveInfoUtils.cnapsCode(s));
                break;
            }
        }

    }

    /**
     * 创建上下文相关的序列化器
     *
     * @param serializerProvider 序列化提供者
     * @param beanProperty Bean属性
     * @return 创建的JsonSerializer
     * @throws JsonMappingException 如果出现映射异常
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        // 为空直接跳过
        if (beanProperty != null) {
            // 非 String 类直接跳过
            if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
                SensitiveWrapped sensitiveWrapped = beanProperty.getAnnotation(SensitiveWrapped.class);
                if (sensitiveWrapped == null) {
                    sensitiveWrapped = beanProperty.getContextAnnotation(SensitiveWrapped.class);
                }
                if (sensitiveWrapped != null) {
                    // 如果能得到注解,就将注解的 value 传入 SensitiveSerialize
                    return new SensitiveSerialize(sensitiveWrapped.value());
                }
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findNullValueSerializer(beanProperty);
    }

    /**
     * 默认构造函数
     */
    public SensitiveSerialize() {}

    /**
     * 带脱敏类型的构造函数
     *
     * @param type 脱敏类型
     */
    public SensitiveSerialize(final SensitiveEnum type) {
        this.type = type;
    }
}

其中createContextual的作用是通过字段已知的上下文信息定制JsonSerializer对象。

编写脱敏工具类

package com.example.desensitization;

import org.apache.commons.lang3.StringUtils;

public class SensitiveInfoUtils {

    /**
     * 将中文全名中的第一个汉字显示出来,其余部分用两个星号隐藏。
     * 例如:李**。
     *
     * @param fullName 中文全名
     * @return 格式化后的姓名,如果输入为空白,则返回空字符串
     */
    public static String chineseName(final String fullName) {
        if (StringUtils.isBlank(fullName)) {
            return "";
        }
        final String name = StringUtils.left(fullName, 1);
        return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
    }

    /**
     * 将中文姓和名合并后,只显示第一个汉字,其他隐藏为2个星号。
     * 例如:李**。
     *
     * @param familyName 姓氏
     * @param givenName 名字
     * @return 格式化后的姓名,如果输入为空白,则返回空字符串
     */
    public static String chineseName(final String familyName, final String givenName) {
        if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) {
            return "";
        }
        return chineseName(familyName + givenName);
    }


    /**
     * 对身份证号进行脱敏处理。
     * 身份证号的前三位和后四位保持不变,中间部分用星号替换。
     * 例如:4201**********5762
     *
     * @param id 身份证号码字符串,可以是15位或18位
     * @return 脱敏后的身份证号码字符串 如果输入为空或者空白字符串,则返回空字符串
     */
    public static String idCardNum(final String id) {
        // 如果身份证号为空或空白字符串,则直接返回空字符串
        if (StringUtils.isBlank(id)) {
            return "";
        }

        // 拼接字符串,前三位加星号填充加后四位
        // StringUtils.left(id, 3) 取字符串的前三位
        // StringUtils.right(id, 4) 取字符串的后四位
        // StringUtils.leftPad 在字符串左侧填充星号,直到达到原字符串长度
        // StringUtils.removeStart 移除左侧开始的三个星号,避免星号覆盖前三位身份证号
        return StringUtils.left(id, 3).concat(StringUtils
                .removeStart(StringUtils.leftPad(StringUtils.right(id, 4), StringUtils.length(id), "*"),
                        "***"));
    }

    /**
     * [固定电话] 后四位,其他隐藏<例子:****1234>
     *
     * @param num 电话号码字符串
     * @return 格式化后的电话号码字符串
     */
    public static String fixedPhone(final String num) {
        if (StringUtils.isBlank(num)) {
            return "";
        }
        // 除了最后四位号码外,其他位数用星号替换
        return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*");
    }

    /**
     * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>
     *
     * @param num 手机号码字符串
     * @return 格式化后的手机号码字符串
     */
    public static String mobilePhone(final String num) {
        if (StringUtils.isBlank(num)) {
            return "";
        }
        // 保留前三位和后四位,中间用星号替换
        return StringUtils.left(num, 3).concat(StringUtils
                .removeStart(StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"),
                        "***"));
    }

    /**
     * [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>
     *
     * @param address 地址字符串
     * @param sensitiveSize 敏感信息长度,即不显示的地址长度
     * @return 格式化后的地址字符串
     */
    public static String address(final String address, final int sensitiveSize) {
        if (StringUtils.isBlank(address)) {
            return "";
        }
        final int length = StringUtils.length(address);
        // 地址的最后几位用星号替换,替换长度为敏感信息长度
        return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*");
    }

    /**
     * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>
     */
    public static String email(final String email) {
        if (StringUtils.isBlank(email)) {
            return "";
        }
        final int index = StringUtils.indexOf(email, "@");
        if (index <= 1) {
            return email;
        } else {
            return StringUtils.rightPad(StringUtils.left(email, 1), index, "*")
                    .concat(StringUtils.mid(email, index, StringUtils.length(email)));
        }
    }

    /**
     * [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>
     */
    public static String bankCard(final 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个星号<例子:12********>
     */
    public static String cnapsCode(final String code) {
        if (StringUtils.isBlank(code)) {
            return "";
        }
        return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*");
    }

}

 编写测试实体类

最后,我们编写一个实体类UserEntity,看看转换后的效果如何

package com.example.desensitization;


public class UserEntity {

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 用户姓名
     */
    private String name;



    /**
     * 手机号
     */
    @SensitiveWrapped(SensitiveEnum.MOBILE_PHONE)
    private String mobile;

    /**
     * 身份证号码
     */
    @SensitiveWrapped(SensitiveEnum.ID_CARD)
    private String idCard;

    /**
     * 年龄
     */
    private String sex;

    /**
     * 性别
     */
    private int age;



    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

当我们想要应用的时候,只需要在想要脱敏的字段上加入注解即可!

测试程序如下:

package com.example.desensitization;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class SensitiveDemo {

    public static void main(String[] args) throws JsonProcessingException {
        UserEntity userEntity = new UserEntity();
        userEntity.setUserId(1l);
        userEntity.setName("张三");
        userEntity.setMobile("18000000001");
        userEntity.setIdCard("420117200001011000008888");
        userEntity.setAge(20);
        userEntity.setSex("男");

        //通过jackson方式,将对象序列化成json字符串
        ObjectMapper objectMapper = new ObjectMapper();
        System.out.println(objectMapper.writeValueAsString(userEntity));
    }
}

结果如下:

{"userId":1,"name":"张三","mobile":"180****0001","idCard":"420*****************8888","sex":"男","age":20}

很清晰的看到,转换结果成功!

如果你当前的项目是基于SpringMVC框架进行开发的,那么在对象返回的时候,框架会自动帮你采用jackson框架进行序列化。

@RequestMapping("/hello")
public UserEntity hello() {
    UserEntity userEntity = new UserEntity();
    userEntity.setUserId(1l);
    userEntity.setName("张三");
    userEntity.setMobile("18000000001");
    userEntity.setIdCard("420117200001011000008888");
    userEntity.setAge(20);
    userEntity.setSex("男");
    return userEntity;
}

请求网页http://127.0.0.1:8080/hello,结果如下:

在实际的业务场景开发中,采用注解方式进行全局数据脱敏处理,可以有效的解决敏感数据隐私泄露的问题。

本文主要从实操层面对数据脱敏处理做了简单的介绍,可能有些网友还有更好的解决方案,欢迎下方留言,后面如果遇到了好的解决办法,也会分享给大家,愿对大家有所帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2110653.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

fantastic-admin前端+django后端,初始化全流程记录

fantastic-admin前端是我目前看到最完善的前端框架&#xff0c;只需要简单的设置就可以快速开始项目。 但是我本人的能力有限&#xff0c;对前端知识一知半解&#xff0c;之前废了九牛二虎之力才跑通了前后端流程&#xff0c;由于新的项目需要&#xff0c;有了开发新后台的想法…

了解PD快充协议和QC快充协议

PD快充协议的实现依赖充电器与设备之间的通信协议&#xff0c;这种通信协议确保了充电器能够提供设备所需要的特定电压和电流。在快充技术中快充协议起到关键角色。 现在市面上最常见的快充协议有PD、QC、华为FCP/SCP、三星AFC协议 、VOOC闪充。PD和QC 协议属于公用协议 。华…

C/C++经典排序问题,sort函数使用

目录 1. 前言 2. 正文 2.1 问题 2.2 解决办法 2.2.1 思路 2.2.2 代码实现 2.2.3 测试结果 3. 备注 1. 前言 大家在学习C语言的时候&#xff0c;是不是经常被排序算法折磨的很难那首&#xff0c;其实都是但是在C中有专门的&#xff0c;排序函数&#xff0c;而且支持自定…

vue系统获取授权平台授权码实现单点登录、注销功能

公司平台需要对接别的平台 实现单点登录 注销。简而言之&#xff0c;不需要在自己公司系统登录 统一在别的平台登录后获取到登录凭证&#xff08;授权码&#xff09; 在本公司系统实现免密登录的功能。 流程&#xff1a; 跳转授权页面和保存授权码的代码&#xff1a; hrefLog…

模型融合创新性好强!最新成果直接登顶SOTA,分分钟拿下顶会

Transformer作者创业新成果火了&#xff01;他们提出了一个70亿参数的日语数学大模型&#xff0c;直接打败700亿参数的Llama-2取得SOTA&#xff01;更牛的是&#xff0c;得出这样的模型无需任何梯度训练&#xff0c;所需计算资源大大减少。 这种炸裂的成果得益于模型融合&…

C++模板(初识)

一、泛型编程 我们平时写交换函数的时候&#xff0c;会这样写&#xff1a; //交换两个int类型变量 void Swap(int& left, int& right) {int temp left;left right;right temp; } //交换两个double类型变量 void Swap(double& left, double& right) {doubl…

随着人们网络安全意识提高,软件架构设计与评估也成为重中之重

目录 案例 【题目】 【问题 1】(13 分) 【问题 2】(12分) 【答案】 【问题 1】答案 【问题 2】答案 相关推荐 案例 阅读以下关于软件架构设计与评估的叙述&#xff0c;回答问题 1 和问题 2。 【题目】 某电子商务公司为正更好地管理用户&#xff0c;提升企业销售业绩&…

Linux中Ubuntu系统安装Windows得字体

背景 安装了geoserver 然后geoserver中需要用到微软雅黑字体 所以需要安装一下Linux系统安装Windows中的字体 创建字体目录 cd /usr/share/fonts/ mkdir winfont在Windows找到对应字体 C:\Windows\Fonts 复制该字体到桌面 Linux系统中上传字体 roottest-server03:/usr/sha…

一键解决物流追踪难题:批量查询工具助力电商运营

探索固乔科技&#xff0c;解锁高效物流查询新纪元&#xff01;固乔快递批量查询助手&#xff0c;一款专为电商、物流从业者及自媒体人打造的神器&#xff0c;让繁琐的物流追踪变得轻松快捷。 想象一下&#xff0c;万级单号批量导入&#xff0c;仅需5分钟&#xff0c;所有物流动…

如何利用mHand Pro动捕数据手套连接虚拟与现实?

数据手套作为虚拟现实中的一种交互动捕设备&#xff0c;能够模拟真人手部的动作和感知反馈&#xff0c;实现人机交互的效果。随着虚拟现实技术的不断发展&#xff0c;数据手套也在不断地改进和升级。 mHand Pro是一款由拥有多年经验的惯性动作捕捉技术团队广州虚拟动力研发的数…

第142天: 内网安全-权限维持黄金白银票据隐藏账户C2 远控RustDeskGotoHTTP

案例一&#xff1a; 内网域&单机版-权限维持-基于用户-隐藏用户 项目下载地址&#xff1a; GitHub - wgpsec/CreateHiddenAccount: A tool for creating hidden accounts using the registry || 一个使用注册表创建隐藏帐户的工具 用这个工具的话在域中会把它加入adminis…

会声会影哪个版本最好用?

会声会影哪个版本最好用? 会声会影2023这个版本是最受欢迎的&#xff0c;它为多数用户提供了稳定且强大的功能。以下是关于为什么这个版本最好用的 一、功能丰富 会声会影X系列版本拥有从视频剪辑、音频编辑到特效添加等全方位的功能。用户可以轻松完成视频的录制、剪辑、转…

SAP ABAP 程序迁移工具 SAPLINK ABAP GIT

SAP ABAP 程序迁移工具 SAPLINK ABAP GIT 1. saplink 这个工具功能挺强大的. 但是使用起来有点麻烦, 需要针对不同的开发对象导入不同的插件.才能处理特定的对象. 而且版本还在不断变化. saplink 项目地址&#xff1a;https://github.com/sapmentors/SAPlink saplink plugin…

鸿蒙轻内核M核源码分析系列六 任务及任务调度(1)任务栈

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 持续更新中…… 继续分析鸿蒙轻内核源码&#xff0c;我们本文开始要分析下任务及任务调度模块。首先&#xff0c;我们介绍下任务栈的基础概念。任务栈是高…

SpringBoot整合Minio及阿里云OSS(配置文件无缝切换)

SpringBoot整合Minio及阿里云OSS 文章目录 SpringBoot整合Minio及阿里云OSS1.Minio安装测试1.Docker安装启动容器 2.创建bucket3.上传文件修改权限 2.SpringBoot整合Minio及阿里云OSS1.公共部分抽取2.Minio配置整合1.添加pom依赖2.添加配置文件3.操作接口实现 3.阿里云OSS配置整…

Class4——Esp32|Thonny两种方式同过电脑控制LED灯,路由器与电脑自带热点连接ESP32

上一节我们通过路由器和设备创建了连接&#xff0c;不懂可按上节配置 Class3——Esp32|Thonny——网络连接主机-wifi连接&#xff08;源代码带教程&#xff09;-CSDN博客文章浏览阅读57次。Esp32|Thonny网络连接主机-wifi连接&#xff08;源代码带教程&#xff09;https://blo…

免费开源的低代码表单FormCreate安装教程,支持可视化设计,适配移动端

低代码表单FormCreate 是一个可以通过 JSON 生成具有动态渲染、数据收集、验证和提交功能的表单生成组件。它支持 6 个 UI 框架&#xff0c;适配移动端&#xff0c;并且支持生成任何 Vue 组件。内置 20 种常用表单组件和自定义组件&#xff0c;再复杂的表单都可以轻松搞定 源码…

网页时装购物:Spring Boot框架的创新应用

第2章相关技术 2.1 B/S架构 B/S结构的特点也非常多&#xff0c;例如在很多浏览器中都可以做出信号请求。并且可以适当的减轻用户的工作量&#xff0c;通过对客户端安装或者是配置少量的运行软件就能够逐步减少用户的工作量&#xff0c;这些功能的操作主要是由服务器来进行控制的…

时尚购物革命:Spring Boot技术在网页时装系统中的应用

第1章 绪论 1.1背景及意义 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们生活水平的不断提高&#xff0c;日常生活中人们对时装购物系统方面的要求也在不断提高&#xff0c;喜欢购物的人数更是不断增加&#xff0c;使得时装购物系统的开发成为必需而且紧迫的…

Rspack 1.0 发布了!

文章来源&#xff5c;Rspack Team 项目地址&#xff5c;https://github.com/web-infra-dev/rspack Rspack 是基于 Rust 编写的下一代 JavaScript 打包工具&#xff0c; 兼容 webpack 的 API 和生态&#xff0c;并提供 10 倍于 webpack 的构建性能。 在 18 个月前&#xff0c;我…