继承JsonSerializer+注解实现自定义数据脱敏方案

1、数据脱敏

数据脱敏是一种保护隐私数据的技术,通过将敏感信息转化为非敏感信息来实现对数据的保护,以保护敏感隐私数据的可靠性和安全性。

数据脱敏可以分为可恢复和不可恢复两类:

  1. 可恢复类可以通过一定的方式恢复成原来的敏感数据。
  2. 不可恢复类则无法被恢复。

在涉及客户安全数据或者一些商业性敏感数据的情况下,在不违反系统规则条件下,如身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏。

2、为何要进行数据脱敏

  1. 保护隐私和数据安全:在处理敏感信息时,如个人身份证号码、银行卡号、电话号码等,通过数据脱敏可以保护该信息不被泄露,提高数据的安全性。
  2. 满足法律法规和合规要求:数据脱敏可以确保数据的合规性,满足相关法律法规和标准的要求。
  3. 防止数据滥用和恶意攻击:数据脱敏可以防止敏感数据被滥用,降低恶意攻击的风险。
  4. 保护企业商业机密:对于包含企业商业机密的数据,通过数据脱敏可以保护其不被泄露,避免对企业造成损失。

在日常的开发中,除了数据脱敏外,还需要将一些敏感的数据从响应中进行剔除,不返回给前端,比如用户信息中的password字段。

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)

可以通过这个注解对指定的字段不进行序列化,前端也就无法收到这个字段。

3、当前市面上普遍的数据脱敏方式

  1. 截断:将敏感数据的某一部分或全部用特殊字符(如*)代替,从而隐藏真实数据。例如将身份证号用“*”替换真实数字。
  2. 随机值:用随机字母或数字代替敏感数据,以保护数据隐私。例如,可以将姓名中的每个字变为随机的相近字。
  3. 数据替换:用一个设定的虚拟值替换真值,从而破坏数据的可读性。例如,可以将手机号统一设置成虚拟手机号。
  4. 仿真:根据敏感数据的原始内容生成符合原始数据编码和校验规则的新数据,使用相同含义的数据替换原有的敏感数据。例如,可以将姓名脱敏后仍然为有意义的姓名,住址脱敏后仍然为住址。

本文就以“截断”为案例进行展示。

4、截断方案

使用截断的方式对数据进行脱敏是一种常见的脱敏方法。它主要是通过对敏感数据的某一部分或全部用特殊字符(如*)或固定字符(如“X”)进行替换,以隐藏敏感信息的真实内容。

这种脱敏方法的主要优点是操作简单,实施方便。同时,由于敏感信息被替换为非敏感字符,因此可以有效地保护敏感数据的隐私。

4.1、前提知识

  1. 熟悉SpringBoot,熟悉SpringBoot默认的序列化方式。
  2. 熟悉正则表达式,使用正则表达式可以简化匹配 / 替换代码。
  3. 熟悉Java8提供的Lamba表达式和内置的函数接口。
  4. 熟悉枚举、注解的使用。

4.2、四大函数式接口

接口名称 描述 方法
Function 通常用于将一个类型的值转换为另一个类型的值。 R apply(T t)
Consumer 通常用于消费一个参数然后执行一些操作 void accept(T t)
Supplier 该接口可以作为数据提供者 T get();
Predicate 通常用于测试一个条件是否成立 boolean test(T t);

熟悉Java8所提供的函数接口,可以简化代码的同时也可以提升代码质量。

4.3、脱敏决策枚举

在枚举中直接使用Function函数接口对数据进行截断替换。

import java.util.function.Function;

/**
 * Created by Time Travel
 * 2023/11/27 17:26
 **/
public enum SensitiveStrategy {
   
    // 身份证
    ID_CARD(s -> s.replaceAll("(\\d{3})\\d{12}(\\w{3})", "$1*****$2")),
    // 手机号
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
    // 地址
    ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}\\S*(\\S{2})", "$1********$2"));

    private final Function<String, String> serialize;

    SensitiveStrategy(Function<String, String> serialize) {
        this.serialize = serialize;
    }

    public Function<String, String> serialize() {
        return serialize;
    }

}

$1和$2分别匹配的是正则中的第一个括号和第二个括号里的内容。

4.4、定义脱敏注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive {
    
    SensitiveStrategy strategy();

}

@JacksonAnnotationsInside:在Jackson中常被用于标记复合注解。当开发者需要将多个Jackson注解组合成一个自定义注解时,就会使用到这个注解。
@JsonSerialize:作用是将java对象序列化为json数据。它常用于字段或get方法上,作用于getter()方法,将java对象序列化为json数据。

4.5、继承JsonSerializer实现序列化

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;

/**
 * Created by Time Travel
 * 2023/11/27 17:27
 **/

public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
    private SensitiveStrategy strategy;

	// 进行序列化
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(strategy.serialize().apply(value));
    }
    
    // 获取属性上的注解属性
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        Sensitive annotation = property.getAnnotation(Sensitive.class);
        if (Objects.nonNull(annotation) && Objects.equals(String.class,
                property.getType().getRawClass())) {
            this.strategy = annotation.strategy();
            return this;
        }
        return prov.findValueSerializer(property.getType(), property);
    }

}

4.6、效果

4.6.1、实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private String nickname;

    @Sensitive(strategy = SensitiveStrategy.PHONE)
    private String phone;

    @Sensitive(strategy = SensitiveStrategy.ID_CARD)
    private String identifyCard;

    @Sensitive(strategy = SensitiveStrategy.ADDRESS)
    private String address;
}

4.6.2、测试结果

继承JsonSerializer+注解实现自定义数据脱敏方案_第1张图片

5、总结

使用数据脱敏方案可以有效地保护隐私和敏感数据的安全,同时满足数据处理和测试等需求,以下是使用数据脱敏方案的总结:

  1. 选择合适的脱敏方案:根据需要保护的数据类型和场景,选择合适的脱敏方案。例如,对于敏感数据的部分字段,可以使用截断或随机值替换;对于需要保持数据完整性的场景,可以使用仿真或数据替换等方案。
  2. 确定脱敏规则和阈值:根据实际需求和风险承受能力,确定脱敏规则和阈值。例如,将手机号码的后四位替换为随机数字,或者将地址中的省市区信息替换为仿真数据等。
  3. 做好数据备份和恢复准备:在进行数据脱敏前,需要做好数据备份,以防止数据丢失或破坏。同时,也需要考虑数据还原的需求,以便在必要时将数据还原为原始状态。
  4. 确保脱敏后的数据质量:在脱敏后,需要确保数据的可用性和准确性。如果脱敏后的数据质量不佳,可能会对数据处理和分析的结果产生负面影响。
  5. 定期更新和审查脱敏方案:随着业务需求和安全威胁的变化,需要定期更新和审查脱敏方案,以确保其有效性和适用性。
  6. 加强人员管理和安全培训:数据脱敏方案只是数据保护的一部分,加强人员管理和安全培训也是非常重要的。需要对开发、测试和运维等人员进行安全意识和技能培训,以减少人为泄露数据的可能性。

你可能感兴趣的:(SpringBoot,spring,boot,spring,cloud,web安全,json,java,后端)