ShardingSphere(四)數據脫敏-實現自定義加密策略

ShardingSphere(四)數據脫敏-實現自定義加密策略

背景

目前官方文檔脫敏部分給出的加密算法的配置都是基於內置的MD5和AES,有很多同學想要自定義加密算法並配置,但是不知道怎麼做。可以參考以下實現過程及思路

注意

以下代碼使用的ShardingSphere版本爲4.1.1

關於數據脫敏詳細的文檔可參考官網數據脫敏部分

自定義加密策略一

實現Encryptor接口

這裏採用SHA256的加密算法,由於SHA256加密是不可逆的。所以解密方法只返回密文

@Getter
@Setter
public final class Sha256Encryptor implements Encryptor {
    
    private Properties properties = new Properties();
    
    @Override
    public void init() {
        
    }
    
    @Override
    public String encrypt(final Object plaintext) {
        if (null == plaintext) {
            return null;
        }
        return DigestUtils.sha256Hex(String.valueOf(plaintext));
    }
    
    @Override
    public Object decrypt(final String ciphertext) {
        return ciphertext;
    }
    
    @Override
    public String getType() {
        return "SHA256";
    }
    
}

在配置文件中配置(基於SpringBoot YAML)

這裏對於要脫敏的字段進行配置,這裏使用了兩種加密策略,對於info字段採用默認的MD5加密,對於name字段採用自定義的SHA256加密

sharding:
  # 數據脫敏規則配置---start
      encrypt-rule:
          encryptors:
            encryptor_sha256:
              # 加密、解密器的名字,內置的爲MD5,aes.
              # 可以自定義,實現
              # com.example.mybatis.demomybatis.shardingsphere.encrypt
              # 或者
              # org.apache.shardingsphere.encrypt.strategy.spi.QueryAssistedEncryptor
              # 這兩個接口即可
              type: SHA256

            encryptor_MD5:
              type: md5
          tables:
            # 數據庫,對應上面分片的tables
             user:
              columns:
                # 邏輯列,就是寫SQL裏面的列,因爲實體類的名字和數據庫的加密列一致,所以這裏都是name
                name:
                  # 密文列,用來存儲密文數據
                  cipherColumn: name
                  # 加密器名字
                  encryptor: encryptor_sha256
                other_info:
                  cipherColumn: info
                  encryptor: encryptor_MD5
      # 數據脫敏規則配置---end

遇到的問題以及定位過程

配置完成之後,便去啓動,此時啓動報錯,報錯提示

Invalid `org.apache.shardingsphere.encrypt.strategy.spi.Encryptor` SPI type `SHA256`.
  1. 根據錯誤找到了拋出異常的位置
    在這裏插入圖片描述

可以看到,是由於集合爲空拋出的異常,那麼這個集合是從哪來的?

  1. 進入loadTypeBasedServices(type)方法中,這個方法裏只做了一件事,獲取當前classtype的集合,並在集合中查找當前type(就是配置的SHA256)
    在這裏插入圖片描述
    可以看到,最終返回的集合裏確實沒有自定義的加密器,上面一行可以看到,result的最終結果都來自SERVICE_MAP中,那麼說明自定義的加密策略並沒有在這個map中
    在這裏插入圖片描述
    map裏確實是沒有

  2. 看來是在啓動的時候沒有把自定義的加密策略放到這個map裏去造成的,通過debug對這個SERVICE_MAP進行watch發現,這個map是在
    在這裏插入圖片描述
    在register這裏加入的,看到這裏的註釋就明白了,官方是通過SPI方式將各個功能通過插件的方式加入整個框架之中。這一點官方文檔也有說。這裏註冊加密策略。可以看到,registerServiceClass這個方法往SERVICE_MAP中添加的元素。直接取決於ServiceLoader.load(srevice)這個方法

  3. 進入ServiceLoader.load

    順着斷點進去,看到reload好像也沒發現什麼,那就先看一下這個類是幹嘛的,於是首先在註釋中找到了答案
    在這裏插入圖片描述
    註釋的前兩段對servie-provider進行了詳細的描述,關鍵在於第三部分,註釋中明確指出了接入service-provider的說明。

    :在項目的resource目錄下,新增配置文件,配置文件位於resource/META-INF/services下,配置文件的名字就是對外提供實現拓展服務的全路徑名字,官方文檔中加密策略對外提供的service的是Encryptor這個接口。配置文件裏的內容就是實現了官方接口的類的全路徑。於是看到這裏,趕緊去配置一下

    後來發現,其實也沒有好好看註釋,在reload方法中註釋表明了,最後會iterator,而最終的路徑,以及路徑裏的內容也是在這裏獲得的
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

在resource目錄下新增配置

配置文件名字爲:org.apache.shardingsphere.encrypt.strategy.spi.Encryptor

配置文件裏的內容,放入自定義的加密策略的類的全路徑,和要使用官方內置的加密策略的類的全路徑

com.example.mybatis.demomybatis.shardingsphere.encrypt.Sha256Encryptor
org.apache.shardingsphere.encrypt.strategy.impl.AESEncryptor
org.apache.shardingsphere.encrypt.strategy.impl.MD5Encryptor
com.example.mybatis.demomybatis.shardingsphere.encrypt.Sha256RandomEncryptor

在這裏插入圖片描述

驗證自定義的加密策略是否生效

請求接口,通過debug自定義加密策略加解密方法、控制檯打印SQL、數據庫查看最終生成的數據、單元測試等手段驗證了加密策略生效
在這裏插入圖片描述

解析

再回頭看看ShardingSphere在配置了加密策略的時候,究竟幹了什麼

  1. ShardingSphere在生成數據源的時候會爲數據源配置具體的ShardingRule

    方法詳情見org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory#createDataSource

  2. 在ShardingRule中會根據配置生成對應的加密策略,以及配置加密策略對應的加密算法

    方法詳情見org.apache.shardingsphere.core.rule.ShardingRule#createEncryptRule

  3. 具體讀取配置文件,以及配置自定義的加密策略是在生成EncryptRule構造方法中的initEncryptors中

    方法詳情見org.apache.shardingsphere.encrypt.rule.EncryptRule#initEncryptors

    這個方法的工作只有兩步

    • 通過執行NewInstanceServiceLoader.register(Encryptor.class)靜態代碼塊,註冊配置的加密策略,通過讀取固定位置下配置文件中的內容將具體的加密策略put進SERVICE_MAP中
    • 根據SERVICE_MAP中的加密策略,創建加密策略的實例,以便在進行數據庫操作時根據配置選擇對應的加密策略進行加密
  4. 在進行數據庫操作時,根據配置的加密策略進行加密

自定義加密策略二

實現QueryAssistedEncryptor接口

至於QueryAssistedEncryptor的應用場景,請閱讀官方文檔數據脫敏部分

@Getter
@Setter
public final class Sha256RandomEncryptor implements QueryAssistedEncryptor {
    
    private Properties properties = new Properties();
    
    @Override
    public String queryAssistedEncrypt(final String plaintext) {
        if (null == plaintext) {
            return null;
        }
        // 原始字符串
        return DigestUtils.sha256Hex(String.valueOf(plaintext));
    }
    
    @Override
    public void init() {
    
    }
    
    @Override
    public String encrypt(final Object plaintext) {
        if (null == plaintext) {
            return null;
        }
        // 原始字符串+變動因子
        byte[] bytes = LocalDateTime.now().toString().getBytes();
        HMac hMac = new HMac(HmacAlgorithm.HmacSHA256, bytes);
        return hMac.digestHex(String.valueOf(plaintext));
    }
    
    @Override
    public Object decrypt(final String ciphertext) {
        return ciphertext;
    }
    
    @Override
    public String getType() {
        return "SHA256_RANDOM";
    }
    
}

以當前時間戳作爲變動因子,或者隨機字符串也可以,對於密文列,採用HMac加密,對於查詢輔助列,則使用普通的SHA256加密

數據表新增same_data子段

在配置文件中配置(基於SpringBoot YAML)

sharding:
  encrypt-rule:
          encryptors:
            encryptor_MD5:
              type: md5
            encryptor_sha256random:
              type: SHA256_RANDOM
          tables:
            # 數據庫,對應上面分片的tables
             user:
              columns:
                # 邏輯列,就是寫SQL裏面的列,因爲實體類的名字和數據庫的加密列一致,所以這裏都是name
                name:
                  # 密文列,用來存儲密文數據
                  cipherColumn: name
                  # 加密器名字
                  encryptor: encryptor_sha256random
                  # 輔助查詢列
                  assistedQueryColumn: same_data
                other_info:
                  cipherColumn: info
                  encryptor: encryptor_MD5

在配置文件中添加自定義的加密策略

在org.apache.shardingsphere.encrypt.strategy.spi.Encryptor文件中配置自定義加密策略

com.example.mybatis.demomybatis.shardingsphere.encrypt.Sha256Encryptor
org.apache.shardingsphere.encrypt.strategy.impl.AESEncryptor
org.apache.shardingsphere.encrypt.strategy.impl.MD5Encryptor
com.example.mybatis.demomybatis.shardingsphere.encrypt.Sha256RandomEncryptor

驗證自定義加密策略是否生效

請求接口,通過debug自定義加密策略加解密方法、控制檯打印SQL、數據庫查看最終生成的數據、單元測試等手段驗證了加密策略生效

  1. 可以看到數據庫裏的數據
    在這裏插入圖片描述
    對於name這個密文列,由於使用了自定義的加密策略,因爲變動因子的原因,所以即使名字相同數據庫裏的存儲也是不同的,而兩條記錄的same_data是一樣的。對於沒有變動因子的MD5加密策略,則info加密之後的存儲信息也是一樣的

  2. 通過name去數據庫進行查詢,即使密文列不相同,但是由於輔助查詢列的存在,ShardingSphere能夠準確的查出數據
    在這裏插入圖片描述

  3. 通過打印SQL發現,輔助查詢列是新增數據的時候,ShardingSphere根據我們的加密策略以及配置的輔助查詢的字段默認插入進去的,改寫的SQL如下
    在這裏插入圖片描述
    ShardingSphere自動幫我們添加了輔助查詢列

結束

以上示例代碼已經放到GitHub上,如需,請自取。地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章