数据脱敏的几种方案

news2024/11/18 15:30:49

文章目录

    • 什么是数据脱敏?
    • 数据脱敏在生活中的应用
    • 静态脱敏与动态脱敏
    • 数据脱敏的几种方案
      • sql数据脱敏
      • java代码实现脱敏
      • mybatis-mate实现脱敏
      • springCloud网关拦截响应体实现脱敏
      • openGauss 动态数据脱敏解决方案

什么是数据脱敏?

数据脱敏也叫数据的去隐私化,采用专门的脱敏算法对敏感数据进行屏蔽和仿真替换,将敏感数据转化为虚构数据,将个人信息匿名化,为数据的安全使用提供基础保障。同时,在不改变业务系统逻辑的前提下,保证脱敏后的数据保留原数据的特征和分布,同时保证数据的有效性和可用性,使脱敏后的数据能够安全地应用于测试、开发、分析和第三方使用环境中。

数据脱敏在生活中的应用

像政府、医疗行业、金融机构、移动运营商是比较早开始应用数据脱敏工具的,因为他们所掌握的都是用户最核心的私密数据,如果泄露后果是不可估量的。

数据脱敏的应用在生活中是比较常见的,比如我们在淘宝买东西订单详情中,商家账户信息会被用 * 遮挡,保障了商户隐私不泄露,这就是一种数据脱敏方式。

静态脱敏与动态脱敏

数据静态脱敏(SDM):适用于将数据抽取出生产环境脱敏后分发至测试、开发、培训、数据分析等场景。

有时我们可能需要将生产环境的数据 copy 到测试、开发库中,以此来排查问题或进行数据分析,但出于安全考虑又不能将敏感数据存储于非生产环境,此时就要把敏感数据从生产环境脱敏完毕之后再在非生产环境使用。

这样脱敏后的数据与生产环境隔离,满足业务需要的同时又保障了生产数据的安全。

数据动态脱敏(DDM): 一般用在生产环境,访问敏感数据时实时进行脱敏,因为有时在不同情况下对于同一敏感数据的读取,需要做不同级别的脱敏处理,例如:不同角色、不同权限所执行的脱敏方案会不同。

数据脱敏的几种方案

sql数据脱敏

-- 电话号码脱敏sql:
 
SELECT mobilePhone AS 脱敏前电话号码,CONCAT(LEF(mobilePhone,3), '********' ) AS 脱敏后电话号码 FROM t_s_user
 
-- 身份证号码脱敏sql:
 
SELECT idcard AS 未脱敏身份证, CONCAT(LEFT(idcard,3), '****' ,RIGHT(idcard,4)) AS 脱敏后身份证号 FROM t_s_user

java代码实现脱敏

/**
* 手机号脱敏
* @param phone 原始手机号信息
* @return 脱敏后信息
*/
public String maskIdNo(String phone){
    // 结果 136****1024
    return phone.replaceAll("(\\w{3})\\w*(\\w{4})", "$1****$2");
}
/**
* 身份证脱敏
* @param idNo 原始身份证号信息
* @return 脱敏后信息
*/
public String maskIdNo(String idNo){
    // 结果 202210******141024
    return idNo.replaceAll("(\\w{6})\\w*(\\w{6})", "$1******$2");
}

mybatis-mate实现脱敏

pom依赖

<dependency><!--MyBatis-Plus 企业级模块-->
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-mate-starter</artifactId>
    <version>1.2.8</version>
</dependency>

YML配置

spring:
  datasource:
    # 配置安全:https://blog.csdn.net/tongxin_tongmeng/article/details/128664932
    url: mpw:IlcV2VrLIr+z3ruf0oHP1sV3JuEvntw9QZDEYhQWDNHJ9Xkm7qZokxkEeTCPNqma
    username: mpw:aoVz0lDJNymnmrhw6LkQow==
    password: mpw:StRVtLG7vB6iKVt83du7fw==
    driver-class-name: com.mysql.cj.jdbc.Driver
 
# Mybatis Mate 配置
mybatis-mate:
  cert:
    # 请添加微信wx153666购买授权,不白嫖从我做起! 测试证书会失效,请勿正式环境使用
    grant: thisIsTestLicense
    license: TtY9GC88CzSkEmUhzIyvM2MJKvsgPyxoNCExH4/GhaBwuTQ93aeLaR6/dM49wMSk+oQdmqUibCM8b5H74s1Nx+2C5V3U1gKiLtddVc8Eg8oC1F2nLxOiDKDvPpdxWFGsPW6mQE2LDr+tK8GXpFS3N8xwmYy/gHCwQ4Avqp9JqBbke7pZzL2adIlxYHmCYpfNTN+NRHIEFaGFTBlzZHDb3UfJaeqLaAtWBol0QOPEM69Kz3JSemxBHnEO1ID75bwwmkgqC7Ps4z9iYAK9GLzzaPwSiFELNCmIvwa5YSJLxP9NMQUWbVGIRqehxnVqfgx/68+yIfpByqGTMxLR33yeEQ==

脱敏策略

@Configuration
public class SensitiveStrategyConfig {
 
    /**
     * 注入脱敏策略
     */
    @Bean
    public ISensitiveStrategy sensitiveStrategy() {
        return new SensitiveStrategy();
    }
 
}

字段脱敏

/**
 * 
 * @TableName sentive
 */
@TableName(value ="sentive")
@Data
public class Sentive implements Serializable {
    /**
     * 主键ID
     */
    @TableId(value = "id")
    private Long id;
 
    /**
     * chineseName
     */
    @FieldSensitive(SensitiveType.chineseName)
    @TableField(value = "chineseName")
    private String chinesename;
 
    /**
     * idCard
     */
    @FieldSensitive(SensitiveType.idCard)
    @TableField(value = "idCard")
    private String idcard;
 
    /**
     * phone
     */
    @FieldSensitive(SensitiveType.phone)
    @TableField(value = "phone")
    private String phone;
 
    /**
     * mobile
     */
    @FieldSensitive(SensitiveType.mobile)
    @TableField(value = "mobile")
    private String mobile;
 
    /**
     * address
     */
    @FieldSensitive(SensitiveType.address)
    @TableField(value = "address")
    private String address;
 
    /**
     * email
     */
    @FieldSensitive(SensitiveType.email)
    @TableField(value = "email")
    private String email;
 
    /**
     * bankCard
     */
    @FieldSensitive(SensitiveType.bankCard)
    @TableField(value = "bankCard")
    private String bankcard;
 
    /**
     * password
     */
    @FieldSensitive(SensitiveType.password)
    @TableField(value = "password")
    private String password;
 
    /**
     * carNumber
     */
    @FieldSensitive(SensitiveType.carNumber)
    @TableField(value = "carNumber")
    private String carnumber;
 
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
 
}

自定义策略

注意:strategyA strategyB strategyC 为自定义脱敏策略,字段添加@FieldSensitive(“strategyA”)注解
即可使用strategyA脱敏策略,该策略将原始数据转为大写后将所有"A"替换为"#",strategyB strategyC同理

@Configuration
public class SensitiveStrategyConfig {
 
    /**
     * 注入脱敏策略
     */
    @Bean
    public ISensitiveStrategy sensitiveStrategy() {
        return new SensitiveStrategy()
                .addStrategy("strategyA", t -> t.toUpperCase().replace("A", "#"))
                .addStrategy("strategyB", t -> t.toUpperCase().replace("B", "$"))
                .addStrategy("strategyC", t -> t.toUpperCase().replace("C", "&"));
 

自定义策略使用

    /**
     * chineseName
     */
    @FieldSensitive("strategyA")
    @TableField(value = "chineseName")
    private String chinesename;
 
    /**
     * idCard
     */
    @FieldSensitive("strategyB")
    @TableField(value = "idCard")
    private String idcard;
 
    /**
     * phone
     */
    @FieldSensitive("strategyC")
    @TableField(value = "phone")
    private String phone;

springCloud网关拦截响应体实现脱敏

@Slf4j
@Component
public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {
    Configuration conf = Configuration.builder()
            .options(Option.AS_PATH_LIST).build();

    @Override
    public int getOrder() {
        return FilterOrderEnum.GATEWAY_CONTEXT_FILTER.getOrder();
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange.mutate().response(responseDecorator(exchange)).build());
    }

    private ServerHttpResponseDecorator responseDecorator(ServerWebExchange exchange) {
        return new ServerHttpResponseDecorator(exchange.getResponse()) {
            ServerHttpResponse serverHttpResponse = exchange.getResponse();
            DataBufferFactory bufferFactory = serverHttpResponse.bufferFactory();

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                return super.writeWith(DataBufferUtils.join(Flux.from(body))
                        .map(dataBuffer -> {
                            // 获取响应体
                            byte[] content = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(content);
                            DataBufferUtils.release(dataBuffer);
                            return content;
                        }).flatMap(bytes -> {
                            // 对响应体进行业务判断(返回值是OK,格式为JSON)
                            if (exchange.getResponse().getStatusCode().equals(HttpStatus.OK)
                                    && exchange.getResponse().getHeaders().get(HttpHeaders.CONTENT_TYPE).get(0).equals(MediaType.APPLICATION_JSON_UTF8.toString())) {
                                // 将响应体转换为String
                                String bodyString = new String(uncompress(bytes), StandardCharsets.UTF_8);
                                log.info("bodyString: {}", bodyString);
                                // 进行业务处理
                                // TODO 调用业务处理方法
                                // 读取配置文件内容
                                List<String> filterField = null;
                                String dataHandling = dataHandling(responseData, filterField);
                                log.info("dataHandling: {}", dataHandling);
                                // 最后将返回的数据类型转换为byte
                                bytes = dataHandling.getBytes();
                            } else {

                            }
                            return Mono.just(bufferFactory.wrap(bytes));
                        }));
            }

            @Override
            public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
            }
        };
    }

    public static byte[] uncompress(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        try {
            GZIPInputStream ungzip = new GZIPInputStream(in);
            byte[] buffer = new byte[256];
            int n;
            while ((n = ungzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
        } catch (IOException e) {
            log.error("gzip uncompress error.", e);
        }

        return out.toByteArray();
    }

    /*编码 gzip*/
    public static byte[] compress(String str, String encoding) {
        if (str == null || str.length() == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip;
        try {
            gzip = new GZIPOutputStream(out);
            gzip.write(str.getBytes(encoding));
            gzip.close();
        } catch (IOException e) {
            log.error("gzip compress error.", e);
        }
        return out.toByteArray();

    }

    public String dataHandling(String responseData, List<String> filterField) {
        try {
            String content = responseData;
            for (String filterFieldS : filterField) {
                //获取所有的节点
                List<String> pathList = JsonPath.using(conf).parse(responseData).read("$.." + filterFieldS);
                for (String path : pathList) {
                    //获取父节点
                    String parentPath = StrUtil.removeSuffix(path, "['" + filterFieldS + "']");
                    //读取值
                    Object json = JsonPath.parse(content).read(path);
                    if (json != null) {
                        String read = json.toString();
                        //脱敏
                        String mobileMask = mask(read);
                        String keyName = filterFieldS + "Mask";
                        //父节点下添加元素
                        content = JsonPath.parse(content).put(parentPath, keyName, mobileMask).jsonString();
                    }
                }
            }
            return content;
        } catch (Exception e) {
            log.error(responseData, e);
        }
        return null;
    }

    public static String mask(String val) {
        if(StrUtil.isBlank(val)){
            return val;
        }
        if(val.length() < 3){
            return StrUtil.hide(val,1,val.length());
        }
        if(val.length() < 4){
            return StrUtil.hide(val,1,val.length()-1);
        }
        if(PhoneUtil.isMobile(val) || PhoneUtil.isMobileHk(val) || PhoneUtil.isMobileTw(val)){
            return StrUtil.desensitized(val,DesensitizedUtil.DesensitizedType.MOBILE_PHONE);
        }
        if(EnumUtil.isEnum(val)){
            return StrUtil.desensitized(val,DesensitizedUtil.DesensitizedType.EMAIL);
        }
        //TODO 银行卡的工具类hutool我没找到可以自行在网上查找
        return StrUtil.desensitized(val, DesensitizedUtil.DesensitizedType.ID_CARD);
    }
}

openGauss 动态数据脱敏解决方案

动态数据脱敏功能在工业界通常以中间插件或数据脱敏系统(Data Masking System)的形态加载,通过在客户端与服务端数据库之间拦截命令或结果集来实现脱敏,而openGauss内置动态数据脱敏特性,使数据库无需借助外部插件就可以实现数据脱敏,有效地降低数据中间传输而导致敏感数据泄漏的风险。

openGauss从1.1.0版本定义了一套完整的内置安全策略模型,基于该模型用户可以定义资源标签来标识敏感数据,针对不同的资源标签类别和内容可定义相关的安全策略机制,而动态数据脱敏就是其中一种。

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

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

相关文章

5款办公必备的好软件,你值得拥有

随着网络信息技术的发展&#xff0c;越来越多的人在办公时需要用到电脑了。如果你想提高办公效率&#xff0c;那么就少不了工具的帮忙&#xff0c;今天给大家分享5款办公必备的好软件。 1.文件管理工具——TagSpaces TagSpaces 是一款开源的文件管理工具,它可以通过标签来组织…

测试20K要什么水平?25岁测试工程师成功斩下offer(附面试题)

年少不懂面试经&#xff0c;读懂已是测试人。 大家好&#xff0c;我是一名历经沧桑&#xff0c;看透互联网行业百态的测试从业者&#xff0c;经过数年的勤学苦练&#xff0c;精钻深研究&#xff0c;终于从初出茅庐的职场新手成长为现在的测试老鸟&#xff0c;早已看透了面试官…

@Test单测方法和main方法的区别

区别1:常量池的符号引用 有所不同 今天在下面链接中 学习并测试 string在不同创建方式下 产生几个对象的问题 流程图详解 new String(“abc“) 创建了几个字符串对象_"new string(\"abc\")创建了几个对象"_程序员囧辉的博客-CSDN博客 看下面例子(取自上…

家居家具行业外贸软件解决方案

家具行业&#xff0c;属于装饰行业范畴&#xff0c;如果出售是零售行业&#xff0c;如果生产属于加工行业&#xff0c;如果是带加工&#xff0c;也可以叫二次加工行业。家居行业&#xff0c;泛指家具、床上用品、厨卫用具、室内配饰及日常生活需要的商品&#xff0c;属于消费产…

Ubuntu 桌面版无网络标识

Ubuntu 配置网络的方式有两种&#xff1a; 通过桌面网络标识直接配置通过编辑配置文件配置&#xff08;很麻烦&#xff0c;而且不方便&#xff09; 因此&#xff0c;下面介绍如何恢复桌面的网络标识&#xff0c;以便于后续的网络配置。 目录 1、修改配置文件 2、删除原本的…

【腾讯云 FinOps Crane 集训营】Crane平台介绍与实践

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN博客专家&#xff0c;阿里云签约博主&#xff0c;InfoQ签约博主&#xff0c;华为云云享专家&#xff0c;51CTO明日之星 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f91e;Crane平台介绍与实践…

腾讯云轻量4核8G12M服务器带宽CPU流量系统盘测评

腾讯云轻量应用服务器4核8G12M带宽&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;2000GB月流量&#xff0c;折合每天66GB流量&#xff0c;系统盘为180GB SSD盘&#xff0c;腾讯云百科来详细说下轻量4核8G12M配置服务器CPU计算性…

【SpringCloud】Eurake注册中心与Ribbon负载均衡原理

目录 一、服务提供者与服务消费者 二、远程调用存在的问题 三、Eureka原理 四、Eureka架构 五、搭建Eureka服务 六、Eureka服务注册 七、Eureka服务发现 八、Ribbon负载均衡流程 九、Ribbon负载均衡源码 十、Ribbon负载均衡策略 十一、Ribbon饥饿加载 一、服务提供者…

【Linux】进程间通信 —— 管道

文章目录 &#x1f4d5; 进程间通信介绍&#x1f4d5; 匿名管道原理使用读写规则特点 &#x1f4d5; 命名管道原理使用匿名管道和命名管道的区别 &#x1f4d5; 进程间通信介绍 进程间通信&#xff0c;顾名思义&#xff0c;就是两个进程之间的 “交流” &#xff0c;我们知道&…

Alibaba开发十年,写出这本“MQ技术手册”,看完我愣住了

前言 消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能&#xff0c;成为异步RPC的主要手段之一。虽然说&#xff0c;目前状况是Kafka更为火热&#xff0c;但更为广泛的应该还属老牌的RabbtiMQ和Alibaba自主…

Android WebRtc+SRS/ZLM视频通话(2):安装SRS

Android WebRtcSRS/ZLM视频通话&#xff08;2&#xff09;&#xff1a;安装SRS 来自奔三人员的焦虑日志 接着上一章内容&#xff0c;继续来安装开源流媒体系统&#xff08;SRS&#xff09;&#xff0c;可以按官方教程或者直接问ChatGPT安装教程&#xff0c;又或者百度一下照着大…

别开玩笑了!特种兵式旅游,胆小勿进!

【大学生特种兵旅游】是什么梗&#xff1f; 最近在多御浏览器上看新闻的时候看到一个热梗【大学生特种兵旅游】这又是什么梗&#xff01;&#xff01;&#xff01;老阿姨震惊了&#xff01; 我随即搜索了一下&#xff0c;看到了下面这段介绍&#xff1a; 近日&#xff0c;“特种…

【SpringBoot集成Nacos+Dubbo】企业级项目集成微服务组件,实现RPC远程调用

文章目录 一、需求环境/版本 二、须知2.1、什么是RPC&#xff1f;2.2、什么是Dubbo&#xff1f;2.3、什么是Nacos&#xff1f; 三、普通的SpringBoot项目集成微服务组件方案&#xff08;笔者给出两种&#xff09;方案一&#xff08;推荐&#xff09;1、导入maven依赖&#xff0…

rocketmq4.9.4 docker安装

rocketmq4.9.4 给对应的路径赋权 chmod -R 777 文件名 不然启动可能报错后者看不到容器日志 systemctl status firewalld 查看防火墙状态 https://www.jianshu.com/p/0c1c3c679ef8 Docker部署RocketMQ&#xff08;4.9.4&#xff09;官方镜像和控制台windows、mac、linux全平…

20230508在Ubuntu22.04下使用python3批量转换DOCX文档为TXT

20230508在Ubuntu22.04下使用python3批量转换DOCX文档为TXT 2023/5/8 16:27 在WIN10下请参考本文&#xff0c;在Ubuntu22.04下需要不通的插件&#xff01; https://blog.csdn.net/weixin_46255747/article/details/129961988 python实现批量docx转txt docx文档放到input目录中。…

Origin如何绘制二维图形?

文章目录 0.引言1.函数绘图2.线图3.符号图4.点线符号图5.柱状/条形/饼图6.多面板/多轴图7.面积图8.专业图9.主题绘图 0.引言 因科研等多场景需要绘制专业的图表&#xff0c;笔者对Origin进行了学习&#xff0c;本文通过《Origin 2022科学绘图与数据》及其配套素材结合网上相关资…

stable diffusion模型讲解

AI模型最新展现出的图像生成能力远远超出人们的预期&#xff0c;直接根据文字描述就能创造出具有惊人视觉效果的图像&#xff0c;其背后的运行机制显得十分神秘与神奇&#xff0c;但确实影响了人类创造艺术的方式。 AI模型最新展现出的图像生成能力远远超出人们的预期&#xf…

PyCharm使用 Anaconda安装TensorFlow

1.安装python全家桶Anaconda 1.1 官网 https://www.anaconda.com/ 进入官网后如下图所示&#xff0c;点击Download即可开始下载&#xff08;若无法下载&#xff0c;请转至清华源下载&#xff09; 1.2 清华 https://repo.anaconda.com/archive/ 2.Anaconda安装 点击Next -…

libssh2交叉编译和测试

目录 官方地址&#xff1a;https://www.libssh2.org/ 1.源码下载 2.交叉编译 3.测试代码 官方地址&#xff1a;https://www.libssh2.org/ 正常来说&#xff0c;看官网说明和例子都能正常编译和使用&#xff0c;想偷个懒的就参考以下步骤。 1.源码下载 我当前看到的版本是li…