成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

金融用戶敏感數據如何優雅地實現脫敏?

開發 前端
Sensitive提供了基于注解的方式,并且內置了常見的脫敏方式,便于開發。

項目介紹

日志脫敏是常見的安全需求。普通的基于工具類方法的方式,對代碼的入侵性太強,編寫起來又特別麻煩。

sensitive[1] 提供了基于注解的方式,并且內置了常見的脫敏方式,便于開發。

日志脫敏

為了金融交易的安全性,國家強制規定對于以下信息是要日志脫敏的:

  1. 用戶名
  2. 手機號
  3. 郵箱
  4. 銀行卡號
  5. 密碼
  6. 身份證號

特性

  1. 基于注解的日志脫敏。
  2. 可以自定義策略實現,策略生效條件。
  3. 內置常見的十幾種脫敏內置方案。
  4. java 深拷貝,且原始對象不用實現任何接口。
  5. 支持用戶自定義注解。
  6. 支持基于 FastJSON 直接生成脫敏后的 json。

快速開始

環境準備

  • JDK 7+
  • Maven 3.x

maven 導入

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>sensitive-core</artifactId>
    <version>1.0.0</version>
</dependency>

核心 api 簡介

SensitiveUtil 工具類的核心方法列表如下:

序號

方法

參數

結果

說明

1

desCopy()

目標對象

深度拷貝脫敏對象

適應性更強

2

desJson()

目標對象

脫敏對象 json

性能較好

3

desCopyCollection()

目標對象集合

深度拷貝脫敏對象集合


4

desJsonCollection()

目標對象集合

脫敏對象 json 集合


定義對象

  • UserAnnotationBean.java

通過注解,指定每一個字段的脫敏策略。

public class UserAnnotationBean {
    @SensitiveStrategyChineseName
    private String username;
    @SensitiveStrategyPassword
    private String password;
    @SensitiveStrategyPassport
    private String passport;
    @SensitiveStrategyIdNo
    private String idNo;
    @SensitiveStrategyCardId
    private String bandCardId;
    @SensitiveStrategyPhone
    private String phone;
    @SensitiveStrategyEmail
    private String email;
    @SensitiveStrategyAddress
    private String address;
    @SensitiveStrategyBirthday
    private String birthday;
    @SensitiveStrategyGps
    private String gps;
    @SensitiveStrategyIp
    private String ip;
    @SensitiveStrategyMaskAll
    private String maskAll;
    @SensitiveStrategyMaskHalf
    private String maskHalf;
    @SensitiveStrategyMaskRange
    private String maskRange;
    //Getter & Setter
    //toString()
}
  • 數據準備

構建一個最簡單的測試對象:

UserAnnotationBean bean  = new UserAnnotationBean();
bean.setUsername("張三");
bean.setPassword("123456");
bean.setPassport("CN1234567");
bean.setPhone("13066668888");
bean.setAddress("中國上海市浦東新區外灘18號");
bean.setEmail("whatanice@code.com");
bean.setBirthday("20220831");
bean.setGps("66.888888");
bean.setIp("127.0.0.1");
bean.setMaskAll("可惡啊我會被全部掩蓋");
bean.setMaskHalf("還好我只會被掩蓋一半");
bean.setMaskRange("我比較靈活指定掩蓋范圍");
bean.setBandCardId("666123456789066");
bean.setIdNo("360123202306018888");
  • 測試代碼
final String originalStr = "UserAnnotationBean{username='張三', password='123456', passport='CN1234567', idNo='360123202306018888', bandCardId='666123456789066', phone='13066668888', email='whatanice@code.com', address='中國上海市浦東新區外灘18號', birthday='20220831', gps='66.888888', ip='127.0.0.1', maskAll='可惡啊我會被全部掩蓋', maskHalf='還好我只會被掩蓋一半', maskRange='我比較靈活指定掩蓋范圍'}";
final String sensitiveStr = "UserAnnotationBean{username='張*', password='null', passport='CN*****67', idNo='3****************8', bandCardId='666123*******66', phone='1306****888', email='wh************.com', address='中國上海********8號', birthday='20*****1', gps='66*****88', ip='127***0.1', maskAll='**********', maskHalf='還好我只會*****', maskRange='我*********圍'}";
final String expectSensitiveJson = "{\"address\":\"中國上海********8號\",\"bandCardId\":\"666123*******66\",\"birthday\":\"20*****1\",\"email\":\"wh************.com\",\"gps\":\"66*****88\",\"idNo\":\"3****************8\",\"ip\":\"127***0.1\",\"maskAll\":\"**********\",\"maskHalf\":\"還好我只會*****\",\"maskRange\":\"我*********圍\",\"passport\":\"CN*****67\",\"phone\":\"1306****888\",\"username\":\"張*\"}";

UserAnnotationBean sensitiveUser = SensitiveUtil.desCopy(bean);
Assert.assertEquals(sensitiveStr, sensitiveUser.toString());
Assert.assertEquals(originalStr, bean.toString());
String sensitiveJson = SensitiveUtil.desJson(bean);
Assert.assertEquals(expectSensitiveJson, sensitiveJson);

我們可以直接利用 sensitiveUser 去打印日志信息,而這個對象對于代碼其他流程不影響,我們依然可以使用原來的 user 對象。

當然,也可以使用 sensitiveJson 打印日志信息。

@Sensitive 注解

說明

@SensitiveStrategyChineseName 這種注解是為了便于用戶使用,本質上等價于 @Sensitive(strategy = StrategyChineseName.class)

@Sensitive 注解可以指定對應的脫敏策略。

內置注解與映射

編號

注解

等價 @Sensitive

備注

1

@SensitiveStrategyChineseName

@Sensitive(strategy = StrategyChineseName.class)

中文名稱脫敏

2

@SensitiveStrategyPassword

@Sensitive(strategy = StrategyPassword.class)

密碼脫敏

3

@SensitiveStrategyEmail

@Sensitive(strategy = StrategyEmail.class)

email 脫敏

4

@SensitiveStrategyCardId

@Sensitive(strategy = StrategyCardId.class)

卡號脫敏

5

@SensitiveStrategyPhone

@Sensitive(strategy = StrategyPhone.class)

手機號脫敏

6

@SensitiveStrategyIdNo

@Sensitive(strategy = StrategyIdNo.class)

身份證脫敏

7

@SensitiveStrategyAddress

@Sensitive(strategy = StrategyAddress.class)

地址脫敏

8

@SensitiveStrategyGps

@Sensitive(strategy = StrategyGps.class)

GPS 脫敏

9

@SensitiveStrategyIp

@Sensitive(strategy = StrategyIp.class)

IP 脫敏

10

@SensitiveStrategyBirthday

@Sensitive(strategy = StrategyBirthday.class)

生日脫敏

11

@SensitiveStrategyPassport

@Sensitive(strategy = StrategyPassport.class)

護照脫敏

12

@SensitiveStrategyMaskAll

@Sensitive(strategy = StrategyMaskAll.class)

全部脫敏

13

@SensitiveStrategyMaskHalf

@Sensitive(strategy = StrategyMaskHalf.class)

一半脫敏

14

@SensitiveStrategyMaskRange

@Sensitive(strategy = StrategyMaskRange.class)

指定范圍脫敏

@Sensitive 定義

@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sensitive {
    /**
     * 注解生效的條件
     * @return 條件對應的實現類
     */
    Class<? extends ICondition> condition() default ConditionAlwaysTrue.class;
    /**
     * 執行的策略
     * @return 策略對應的類型
     */
    Class<? extends IStrategy> strategy();


}

與 @Sensitive 混合使用

如果你將新增的注解 @SensitiveStrategyChineseName 與 @Sensitive 同時在一個字段上使用。

為了簡化邏輯,優先選擇執行 @Sensitive,如果 @Sensitive 執行脫敏, 那么 @SensitiveStrategyChineseName 將不會生效。

如:

/**
 * 測試字段
 * 1.當多種注解混合的時候,為了簡化邏輯,優先選擇 @Sensitive 注解。
 */
@SensitiveStrategyChineseName
@Sensitive(strategy = StrategyPassword.class)
private String testField;

更多特性

自定義脫敏策略生效的場景

默認情況下,我們指定的場景都是生效的。

但是你可能需要有些情況下不進行脫敏,比如有些用戶密碼為 123456,你覺得這種用戶不脫敏也罷。

  • UserPasswordCondition.java
@Sensitive(condition = ConditionFooPassword.class, strategy = StrategyPassword.class)
private String password;

其他保持不變,我們指定了一個 condition,實現如下:

  • ConditionFooPassword.java
public class ConditionFooPassword implements ICondition {
    @Override
    public boolean valid(IContext context) {
        try {
            Field field = context.getCurrentField();
            final Object currentObj = context.getCurrentObject();
            final String password = (String) field.get(currentObj);
            return !password.equals("123456");
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

也就是只有當密碼不是 123456 時密碼脫敏策略才會生效。

屬性為集合或者對象

如果某個屬性是單個集合或者對象,則需要使用注解 @SensitiveEntry

  • 放在集合屬性上,且屬性為普通對象

會遍歷每一個屬性,執行上面的脫敏策略。

  • 放在對象屬性上

會處理對象中各個字段上的脫敏注解信息。

  • 放在集合屬性上,且屬性為對象

遍歷每一個對象,處理對象中各個字段上的脫敏注解信息。

放在集合屬性上,且屬性為普通對象

  • UserEntryBaseType.java

作為演示,集合中為普通的字符串。

public class UserEntryBaseType {
    @SensitiveEntry
    @Sensitive(strategy = StrategyChineseName.class)
    private List<String> chineseNameList;
    @SensitiveEntry
    @Sensitive(strategy = StrategyChineseName.class)
    private String[] chineseNameArray;
    //Getter & Setter & toString()
}

放在對象屬性上

例子如下:

public class UserEntryObject {
    @SensitiveEntry
    private User user;
    @SensitiveEntry
    private List<User> userList;
    @SensitiveEntry
    private User[] userArray;
    //...
}

自定義注解

  • v0.0.4 新增功能。允許功能自定義條件注解和策略注解。?v0.0.11 新增功能。允許功能自定義級聯脫敏注解。

案例1

自定義密碼脫敏策略&自定義密碼脫敏策略生效條件

  • 策略脫敏
/**
 * 自定義密碼脫敏策略
 * @author binbin.hou
 * date 2019/1/17
 * @since 0.0.4
 */
@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@SensitiveStrategy(CustomPasswordStrategy.class)
public @interface SensitiveCustomPasswordStrategy {
}
  • 脫敏生效條件
/**
 * 自定義密碼脫敏策略生效條件
 * @author binbin.hou
 * date 2019/1/17
 * @since 0.0.4
 */
@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@SensitiveCondition(ConditionFooPassword.class)
public @interface SensitiveCustomPasswordCondition{
}
  • TIPS

@SensitiveStrategy 策略單獨使用的時候,默認是生效的。

如果有 @SensitiveCondition 注解,則只有當條件滿足時,才會執行脫敏策略。

@SensitiveCondition 只會對系統內置注解和自定義注解生效,因為 @Sensitive 有屬于自己的策略生效條件。

  • 策略優先級

@Sensitive 優先生效,然后是系統內置注解,最后是用戶自定義注解。

對應的實現

兩個元注解 @SensitiveStrategy@SensitiveCondition 分別指定了對應的實現。

  • CustomPasswordStrategy.java
public class CustomPasswordStrategy implements IStrategy {
    @Override
    public Object des(Object original, IContext context) {
        return "**********************";
    }
}
  • ConditionFooPassword.java
/**
 * 讓這些 123456 的密碼不進行脫敏
 * @author binbin.hou
 * date 2019/1/2
 * @since 0.0.1
 */
public class ConditionFooPassword implements ICondition {
    @Override
    public boolean valid(IContext context) {
        try {
            Field field = context.getCurrentField();
            final Object currentObj = context.getCurrentObject();
            final String name = (String) field.get(currentObj);
            return !name.equals("123456");
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

定義測試對象

定義一個使用自定義注解的對象。

public class CustomPasswordModel {
    @SensitiveCustomPasswordCondition
    @SensitiveCustomPasswordStrategy
    private String password;
    @SensitiveCustomPasswordCondition
    @SensitiveStrategyPassword
    private String fooPassword;
    //其他方法
}

測試

/**
 * 自定義注解測試
 */
@Test
public void customAnnotationTest() {
    final String originalStr = "CustomPasswordModel{password='hello', fooPassword='123456'}";
    final String sensitiveStr = "CustomPasswordModel{password='**********************', fooPassword='123456'}";
    CustomPasswordModel model = buildCustomPasswordModel();
    Assert.assertEquals(originalStr, model.toString());
    CustomPasswordModel sensitive = SensitiveUtil.desCopy(model);
    Assert.assertEquals(sensitiveStr, sensitive.toString());
    Assert.assertEquals(originalStr, model.toString());
}

構建對象的方法如下:

/**
 * 構建自定義密碼對象
 * @return 對象
 */
private CustomPasswordModel buildCustomPasswordModel(){
    CustomPasswordModel model = new CustomPasswordModel();
    model.setPassword("hello");
    model.setFooPassword("123456");
    return model;
}

案例2

  • v0.0.11 新增功能。允許功能自定義級聯脫敏注解。

自定義級聯脫敏注解

  • 自定義級聯脫敏注解

可以根據自己的業務需要,在自定義的注解上使用 @SensitiveEntry

使用方式保持和 @SensitiveEntry 一樣即可。

/**
 * 級聯脫敏注解,如果對象中屬性為另外一個對象(集合),則可以使用這個注解指定。
 * <p>
 * 1. 如果屬性為 Iterable 的子類集合,則當做列表處理,遍歷其中的對象
 * 2. 如果是普通對象,則處理對象中的脫敏信息
 * 3. 如果是普通字段/MAP,則不做處理
 * @since 0.0.11
 */
@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@SensitiveEntry
public @interface SensitiveEntryCustom {
}

定義測試對象

定義一個使用自定義注解的對象。

public class CustomUserEntryObject {
    @SensitiveEntryCustom
    private User user;
    @SensitiveEntryCustom
    private List<User> userList;
    @SensitiveEntryCustom
    private User[] userArray;
    // 其他方法...
}

生成脫敏后的 JSON

說明

為了避免生成中間脫敏對象,v0.0.6 之后直接支持生成脫敏后的 JSON。

使用方法

新增工具類方法,可以直接返回脫敏后的 JSON。

生成的 JSON 是脫敏的,原對象屬性值不受影響。

public static String desJson(Object object)

注解的使用方式

和 SensitiveUtil.desCopy() 完全一致。

使用示例代碼

所有的測試案例中,都添加了對應的 desJson(Object) 測試代碼,可以參考。

此處只展示最基本的使用。

final String originalStr = "SystemBuiltInAt{phone='18888888888', password='1234567', name='脫敏君', email='12345@qq.com', cardId='123456190001011234'}";
final String sensitiveJson = "{\"cardId\":\"123456**********34\",\"email\":\"12******.com\",\"name\":\"脫**\",\"phone\":\"1888****888\"}";
SystemBuiltInAt systemBuiltInAt = DataPrepareTest.buildSystemBuiltInAt();
Assert.assertEquals(sensitiveJson, SensitiveUtil.desJson(systemBuiltInAt));
Assert.assertEquals(originalStr, systemBuiltInAt.toString());

注意

本次 JSON 脫敏基于 FastJSON[2]

FastJSON 在序列化本身存在一定限制。當對象中有集合,集合中還是對象時,結果不盡如人意。

示例代碼

本測試案例可見測試代碼。

final String originalStr = "UserCollection{userList=[User{username='脫敏君', idCard='123456190001011234', password='1234567', email='12345@qq.com', phone='18888888888'}], userSet=[User{username='脫敏君', idCard='123456190001011234', password='1234567', email='12345@qq.com', phone='18888888888'}], userCollection=[User{username='脫敏君', idCard='123456190001011234', password='1234567', email='12345@qq.com', phone='18888888888'}], userMap={map=User{username='脫敏君', idCard='123456190001011234', password='1234567', email='12345@qq.com', phone='18888888888'}}}";
final String commonJson = "{\"userArray\":[{\"email\":\"12345@qq.com\",\"idCard\":\"123456190001011234\",\"password\":\"1234567\",\"phone\":\"18888888888\",\"username\":\"脫敏君\"}],\"userCollection\":[{\"$ref\":\"$.userArray[0]\"}],\"userList\":[{\"$ref\":\"$.userArray[0]\"}],\"userMap\":{\"map\":{\"$ref\":\"$.userArray[0]\"}},\"userSet\":[{\"$ref\":\"$.userArray[0]\"}]}";
final String sensitiveJson = "{\"userArray\":[{\"email\":\"12******.com\",\"idCard\":\"123456**********34\",\"phone\":\"1888****888\",\"username\":\"脫**\"}],\"userCollection\":[{\"$ref\":\"$.userArray[0]\"}],\"userList\":[{\"$ref\":\"$.userArray[0]\"}],\"userMap\":{\"map\":{\"$ref\":\"$.userArray[0]\"}},\"userSet\":[{\"$ref\":\"$.userArray[0]\"}]}";
UserCollection userCollection = DataPrepareTest.buildUserCollection();
Assert.assertEquals(commonJson, JSON.toJSONString(userCollection));
Assert.assertEquals(sensitiveJson, SensitiveUtil.desJson(userCollection));
Assert.assertEquals(originalStr, userCollection.toString());

解決方案

如果有這種需求,建議使用原來的 desCopy(Object)

脫敏引導類

為了配置的靈活性,引入了引導類。

核心 api 簡介

SensitiveBs 引導類的核心方法列表如下:

序號

方法

參數

結果

說明

1

desCopy()

目標對象

深度拷貝脫敏對象

適應性更強

2

desJson()

目標對象

脫敏對象 json

性能較好

使用示例

使用方式和工具類一致,示意如下:

SensitiveBs.newInstance().desCopy(user);

配置深度拷貝實現

默認的使用 FastJson 進行對象的深度拷貝,等價于:

SensitiveBs.newInstance()
                .deepCopy(FastJsonDeepCopy.getInstance())
                .desJson(user);

參見 SensitiveBsTest.java[3]。

deepCopy 用于指定深度復制的具體實現,支持用戶自定義。

深度復制(DeepCopy)

說明

深度復制可以保證我們日志輸出對象脫敏,同時不影響正常業務代碼的使用。

可以實現深度復制的方式有很多種,默認基于 fastjson[4] 實現的。

為保證后續良性發展,v0.0.13 版本之后將深度復制接口抽離為單獨的項目:

deep-copy[5]

內置策略

目前支持 6 種基于序列化實現的深度復制,便于用戶替換使用。

每一種都可以單獨使用,保證依賴更加輕量。

自定義

為滿足不同場景的需求,深度復制策略支持用戶自定義。

自定義深度復制[6]

開源地址

https://github.com/houbb/sensitive [7]。

References

[1] sensitive: https://github.com/houbb/sensitive。

[2] FastJSON: https://github.com/alibaba/fastjson。

[3] SensitiveBsTest.java: https://github.com/houbb/sensitive/blob/master/sensitive-test/src/test/java/com/github/houbb/sensitive/test/bs/SensitiveBsTest.java。

[4] fastjson: https://github.com/alibaba/fastjson。

[5] deep-copy: https://github.com/houbb/deep-copy。

[6] 自定義深度復制: https://github.com/houbb/deep-copy#自定義。

[7] https://github.com/houbb/sensitive : https://github.com/houbb/sensitive。

責任編輯:姜華 來源: 今日頭條
相關推薦

2023-10-07 08:34:27

項目API接口

2021-09-16 10:11:15

Dataphin 數據保護

2010-09-25 08:55:29

2024-09-27 12:27:31

2020-10-25 09:04:46

數據加密數據泄露攻擊

2023-07-21 12:48:37

2025-06-18 02:12:00

2024-03-05 09:40:35

2020-04-16 08:00:00

Ansible Vau敏感數據加密

2018-09-14 14:48:01

2020-12-08 08:08:51

Java接口數據

2022-05-24 06:07:48

JShack用戶代碼

2024-01-01 15:53:25

2023-10-23 10:39:05

2020-11-26 15:09:49

數據安全百度地圖機器學習

2012-07-03 11:35:02

數據安全

2021-05-12 22:07:43

并發編排任務

2023-06-27 07:26:36

汽車之家敏感數據治理

2024-08-08 10:32:11

2024-12-09 08:27:59

敏感數據加密
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级片免费视频 | 国产欧美精品区一区二区三区 | 精品九九九 | 噜久寡妇噜噜久久寡妇 | 欧美日日| 久久亚洲一区二区三区四区 | 国产探花在线精品一区二区 | 国产黄色在线观看 | 亚洲人成在线观看 | 一区二区三区视频在线免费观看 | 日韩视频在线播放 | 日韩电影中文字幕在线观看 | 久久大 | 日本人做爰大片免费观看一老师 | 日本欧美国产 | 日韩一区二区在线视频 | 亚洲精品乱码久久久久久按摩观 | 日本久草视频 | 超碰91在线 | 久久国产高清 | 国产欧美一区二区精品久导航 | 免费av手机在线观看 | 老牛嫩草一区二区三区av | 涩涩视频大全 | 涩涩操 | 嫩草影院网址 | 国产精品视频在线播放 | 国产一区二区小视频 | 国产精品视频一二三区 | 中文字幕一区二区三区乱码在线 | 超碰欧美 | 91欧美激情一区二区三区成人 | 亚洲国产精品一区二区久久 | 久久精品国产一区二区 | 久久成人免费视频 | 日日操日日干 | 国产高清在线精品 | 日本三级线观看 视频 | 一区二区三区精品 | 狠狠天天 | 999久久久久久久 |