亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java數(shù)據(jù)脫敏實(shí)現(xiàn)的方法總結(jié)

 更新時(shí)間:2023年07月25日 11:02:10   作者:十年培訓(xùn)經(jīng)驗(yàn)的菜包  
數(shù)據(jù)脫敏,指的是對(duì)某些敏感信息通過(guò)脫敏規(guī)則進(jìn)行數(shù)據(jù)的變形,實(shí)現(xiàn)敏感隱私數(shù)據(jù)的可靠保護(hù),本文主要是對(duì)后端數(shù)據(jù)脫敏實(shí)現(xiàn)的簡(jiǎn)單總結(jié),希望對(duì)大家有所幫助

什么是數(shù)據(jù)脫敏

數(shù)據(jù)脫敏,指的是對(duì)某些敏感信息通過(guò)脫敏規(guī)則進(jìn)行數(shù)據(jù)的變形,實(shí)現(xiàn)敏感隱私數(shù)據(jù)的可靠保護(hù)。摘自百度百科數(shù)據(jù)脫敏。

對(duì)數(shù)據(jù)進(jìn)行脫敏的操作一般是不可逆的。

脫敏內(nèi)容

一般來(lái)說(shuō),脫敏內(nèi)容包含但不限于各種隱私數(shù)據(jù)或商業(yè)性敏感數(shù)據(jù),如身份證號(hào)、手機(jī)、郵箱、營(yíng)業(yè)執(zhí)照、銀行卡號(hào)等信息,具體要求需要根據(jù)不同公司業(yè)務(wù)而定。

脫敏場(chǎng)景

前端頁(yè)面內(nèi)容

我司系統(tǒng)都是前后端分離的系統(tǒng),脫敏方案都是在序列化層面來(lái)做,具體的實(shí)現(xiàn)也是基于各序列化庫(kù),如jackson、fastjson。

Jackson實(shí)現(xiàn)

Jackson需要自定義一個(gè)序列化器

public class JacksonDataMaskSerializer extends StdSerializer<String> implements ContextualSerializer {
    //脫敏策略枚舉
 ? ?private DataMaskType dataMask;
 ? ?protected JacksonDataMaskSerializer() {
 ? ? ? ?super(String.class);
 ?  }
?
 ? ?@Override
 ? ?public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
 ? ? ? ?JacksonDataMask jacksonDataMask = property.getAnnotation(JacksonDataMask.class);
 ? ? ? ?if (jacksonDataMask != null && String.class.equals(property.getType().getRawClass())){
 ? ? ? ? ? ?dataMask = jacksonDataMask.maskType();
 ? ? ? ? ? ?return this;
 ? ? ?  }
 ? ? ? ?return prov.findContentValueSerializer(property.getType(),property);
 ?  }
?
 ? ?@Override
 ? ?public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
 ? ?    //執(zhí)行脫敏
 ? ? ? ?String resultValue = dataMask.getStrategy().process(value,dataMask.getParams());
 ? ? ? ?gen.writeString(resultValue);
 ?  }
}

由于不同字段需要使用的脫敏規(guī)則是不同的,所以直接使用@JsonSerialize(contentUsing = JacksonDataMaskSerializer.class)并沒(méi)有什么意義,我們需要通過(guò)自定義Jackson的注解,來(lái)實(shí)現(xiàn)一個(gè)Serializer滿足不同脫敏工作,自定義注解如下

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = JacksonDataMaskSerializer.class)
public @interface JacksonDataMask {
?
 ? ?/**
 ? ? * 脫敏策略
 ? ? */
 ? ?DataMaskType maskType() default DataMaskType.Default;
}

可以看到,使用@JacksonAnnotationsInside注解,來(lái)實(shí)現(xiàn)Jackson的自定義注解功能,這樣即可滿足不同字段的脫敏要求,使用姿勢(shì)如下:

@Data
public class DemoVo{
 ? ?@JacksonDataMask(maskType = DataMaskType.Phone)
    private String phone;
 ? ?@JacksonDataMask(maskType = DataMaskType.Mail)
    private String email;
}

至于脫敏策略規(guī)則枚舉,非常簡(jiǎn)單,就不寫(xiě)了,無(wú)非就是不同策略對(duì)字段值的部分字符替換成特殊字符,常見(jiàn)的如”*“;

Fastjson實(shí)現(xiàn)

Fastjson的實(shí)現(xiàn)與Jackson類(lèi)似,也是自定義序列化攔截器,讀取字段上注解,然后使用注解策略進(jìn)行脫敏處理,具體實(shí)現(xiàn)略。

導(dǎo)出數(shù)據(jù)內(nèi)容

常見(jiàn)導(dǎo)出數(shù)據(jù)的形式為導(dǎo)出excel,使用的導(dǎo)出excel工具庫(kù)如easyexcel、easypoi等,此處以easyexcel為例。

我們同樣需要自定義一個(gè)注解,如下:

public @interface ExcelDataMask {
?
 ? ?/**
 ? ? * 脫敏策略
 ? ? */
 ? ?DataMaskType maskType() default DataMaskType.Default;
}

看起來(lái)是不是與前面介紹序列化庫(kù)時(shí)自定義的注解一樣,其實(shí)直接使用前面的也沒(méi)問(wèn)題,本質(zhì)上是標(biāo)志該字段的數(shù)據(jù)需要脫敏,以便不同實(shí)現(xiàn)的代碼可以識(shí)別。

有了自定義注解后,按照Excel官方demo,并在DTO字段上進(jìn)行注解。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class DemoItemDto {
?
 ? ?@ExcelProperty("手機(jī)號(hào)碼")
 ? ?@ExcelDataMask(maskType=DataMaskType.PHONE)
 ? ?private String phone;
}
EasyExcel.write("/demo.xlsx", DemoItemDto.class).registerWriteHandler(new CellWriteHandler() {
 ? ? ? ? ? ?@Override
 ? ? ? ? ? ?public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData<?> cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
 ? ? ? ? ? ? ? ?if (isHead){
 ? ? ? ? ? ? ? ? ? ?//head不需要脫敏
 ? ? ? ? ? ? ? ? ? ?return;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ? ? ? ?ExcelDataMask excelDataMask = head.getField().getAnnotation(ExcelDataMask.class);
 ? ? ? ? ? ? ? ?if (excelDataMask == null) {
 ? ? ? ? ? ? ? ? ? ?return;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ? ? ? ?DataMaskType dataMaskType = excelDataMask.maskType();
 ? ? ? ? ? ? ? ?if (dataMaskType == null) {
 ? ? ? ? ? ? ? ? ? ?return;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ? ? ? ?String stringValue = cellData.getStringValue();
 ? ? ? ? ? ? ? ?if (StrUtil.isNotBlank(stringValue)) {
 ? ? ? ? ? ? ? ?    //數(shù)據(jù)脫敏后重新寫(xiě)入
 ? ? ? ? ? ? ? ? ? ?cellData.setStringValue(dataMaskType.process(stringValue));
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }).sheet("模板").doWrite(list);

至此,一個(gè)簡(jiǎn)單的excel導(dǎo)出內(nèi)容脫敏注解就完成了。

系統(tǒng)日志內(nèi)容

在有嚴(yán)格安全規(guī)范要求公司,系統(tǒng)運(yùn)行時(shí)打印的日志內(nèi)容也是需要脫敏的。

常見(jiàn)的日志框架無(wú)非是logback、log4j這些(slf4j只是一個(gè)門(mén)面,不提供具體日志實(shí)現(xiàn)),基本上使用方法最終都是一句log.xx來(lái)實(shí)現(xiàn)打印。此處簡(jiǎn)單以打印json字符串為例

log.info("內(nèi)容:{}",JSON.toJsonString(dto));

一般來(lái)說(shuō),有兩種方案。

方案一(不推薦)

自定義dto轉(zhuǎn)json字符串的方案,使用json序列化攔截器進(jìn)行脫敏,這種類(lèi)似方案,比較知名的實(shí)現(xiàn)如唯品會(huì)脫敏方案

該方案有明顯的缺點(diǎn),即需對(duì)分散在代碼中的所有l(wèi)og打印進(jìn)行改造,工作量大,并且容易遺漏。

方案二

該方案是將脫敏邏輯,與業(yè)務(wù)代碼剝離開(kāi),在日志框架層面進(jìn)行實(shí)現(xiàn)。以logback為例,可以從以下兩個(gè)擴(kuò)展點(diǎn)進(jìn)行實(shí)現(xiàn)。

自定義PatternLayout

在使用logback時(shí),一般會(huì)自定義日志輸出內(nèi)容格式,使用PatternLayout來(lái)格式化,類(lèi)似如下

<!-- CONSOLE Appender -->
 ? ?<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
 ? ? ? ?<layout class="ch.qos.logback.classic.PatternLayout">
 ? ? ? ? ? ?<pattern>
 ? ? ? ? ? ? ?  d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
 ? ? ? ? ? ?</pattern>
 ? ? ? ?</layout>
 ? ?</appender>

直接自定義PatternLayout對(duì)msg進(jìn)行脫敏

public class DataMaskingPatternLayout extends PatternLayout {
 ? ?@Override
 ? ?public String doLayout(ILoggingEvent event) {
 ? ? ? ?String msg = super.doLayout(event);
 ? ?    //字符串脫敏處理
 ? ?    return doMask(msg);
 ?  }
}

存在的問(wèn)題

  • 脫敏處理的對(duì)象是字符串,脫敏內(nèi)容的識(shí)別需要使用多種正則匹配;
  • 無(wú)論是否有入?yún)?、是否有敏感字段,所有日志?nèi)容都需要執(zhí)行多種正則匹配;

可以看到,自定義PatternLayout的性能相對(duì)來(lái)說(shuō)是比較低的,所以實(shí)際項(xiàng)目上并不推薦該方案。

自定義Converter(推薦)

自定義PatternLayout是對(duì)格式化后的字符串進(jìn)行脫敏,可拓展性較差。實(shí)際項(xiàng)目中,為了識(shí)別不同的日志信息后脫敏,更多的是自定義日志格式轉(zhuǎn)換器Converter來(lái)實(shí)現(xiàn)脫敏。簡(jiǎn)單看下如何使用

//ClassicConverter是一個(gè)抽象類(lèi),是Converter的子類(lèi)
public class DataMaskingConverter extends ClassicConverter {
 ? ?@Override
 ? ?public String convert(ILoggingEvent event) {
 ? ? ? ?if (event == null) {
 ? ? ? ? ? ?return null;
 ? ? ?  }
 ? ?    //log參數(shù)脫敏
 ? ?    Object[] maskArgs = argsToMask(event.getArgumentArray());
 ? ?    //參數(shù)脫敏后參與格式化
 ? ?    String msg = MessageFormatter.arrayFormat(event.getMessage(),maskArgs).getMessage();
 ? ? ? ?return msg;
 ?  }
 ? ?@Override
 ? ?public Object[] argsToMask(Object[] argumentArray) {
 ? ? ? ?if (argumentArray == null) {
 ? ? ? ? ? ?return null;
 ? ? ?  }
 ? ? ? ?Object[] res = new Object[argumentArray.length];
 ? ? ? ?int i = 0;
 ? ? ? ?for (Object arg : argumentArray) {
 ? ? ? ? ? ?if (arg == null || arg instanceof Throwable) {
 ? ? ? ? ? ? ? ?res[i] = arg;
 ? ? ? ? ? ? ? ?continue;
 ? ? ? ? ?  }
 ? ? ? ?    if (ObjectUtil.isBasicType(arg)) {
 ? ? ? ? ? ?    if(arg instanceof String && JsonUtil.isJson(arg)){
 ? ? ? ? ? ? ? ? ?//json字符串
 ? ? ? ? ? ? ?    res[i] = DataMask.maskJsonStr(arg);
 ? ? ? ? ? ? ?  } else {
 ? ? ? ? ? ? ? ? ?//其他基礎(chǔ)數(shù)據(jù)類(lèi)型
 ? ? ? ? ? ? ? ? ?res[i] = arg;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ? ?    continue;
 ? ? ? ? ?  } 
 ? ? ? ?    if {
 ? ? ? ? ? ?    //其他對(duì)象
 ? ? ? ? ? ? ? ?res[i] = DataMask.toJSONString(arg);
 ? ? ? ? ?  }
 ? ? ? ? ? ?i++;
 ? ? ?  }
 ? ? ? ?return res;
 ?  }
}

在logback配置文件中,新增配置

<configuration>
    <!-- conversionWord="msg",其中msg就是對(duì)應(yīng)pattern標(biāo)簽中的msg -->
 ? ?<conversionRule conversionWord="msg" ?converterClass="cn.cc.DataMaskingConverter"/>
</configuration>

可以看到,自定義Converter可以對(duì)入?yún)⒌念?lèi)型來(lái)選擇不同的脫敏操作,相對(duì)PatternLayout來(lái)說(shuō),減少大量正則匹配,大幅提高性能。此時(shí)log.info("內(nèi)容:{}",JSON.toJsonString(dto)) 需要改寫(xiě)成log.info("內(nèi)容:{}",dto)。

但自定義Converter也存在一些問(wèn)題

  • 對(duì)于入?yún)⑹亲址娜罩荆鏻og.info("xx",JSON.toJsonString(dto))、log.info("xx",dto.toString()),如果字符串中包含敏感字段,想要識(shí)別,只能通過(guò)多種正則進(jìn)行匹配;
  • 若直接使用log.info()方法沒(méi)有參數(shù),直接打印字符串的話,如果字符串中包含敏感字段,且需要進(jìn)行脫敏處理,則自定義Converter也將退化成類(lèi)似前面自定義PatternLayout,只能使用正則匹配的方法實(shí)現(xiàn)脫敏。

針對(duì)自定義Converter存在的問(wèn)題,在實(shí)際項(xiàng)目中可以發(fā)現(xiàn),如果想要單獨(dú)依賴(lài)自定義Converter完全解決日志脫敏的問(wèn)題,是非常困難的,因此有以下建議

  • log的方法使用時(shí),盡量帶上參數(shù);
  • 盡量避免入?yún)镾tring;

到此這篇關(guān)于Java數(shù)據(jù)脫敏實(shí)現(xiàn)的方法總結(jié)的文章就介紹到這了,更多相關(guān)Java數(shù)據(jù)脫敏內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用ShardingJDBC進(jìn)行數(shù)據(jù)分片以及讀寫(xiě)分離

    使用ShardingJDBC進(jìn)行數(shù)據(jù)分片以及讀寫(xiě)分離

    ShardingJDBC是一個(gè)輕量級(jí)的Java框架,提供了數(shù)據(jù)分片、讀寫(xiě)分離、分布式主鍵生成等數(shù)據(jù)訪問(wèn)功能,本文將給大家介紹如何使用ShardingJDBC進(jìn)行數(shù)據(jù)分片以及讀寫(xiě)分離,需要的朋友可以參考下
    2024-01-01
  • Java線程池詳細(xì)解讀

    Java線程池詳細(xì)解讀

    這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • spring boot--從controller到DAO操作

    spring boot--從controller到DAO操作

    這篇文章主要介紹了spring boot--從controller到DAO操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Spring?Boot簡(jiǎn)單實(shí)現(xiàn)文件上傳功能

    Spring?Boot簡(jiǎn)單實(shí)現(xiàn)文件上傳功能

    這篇文章主要介紹了Spring?Boot簡(jiǎn)單實(shí)現(xiàn)文件上傳功能,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08
  • Spring?MVC數(shù)據(jù)綁定方式

    Spring?MVC數(shù)據(jù)綁定方式

    這篇文章主要介紹了Spring?MVC數(shù)據(jù)綁定方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • 最新評(píng)論