新聞中心
安全控制一直是治理的重要環(huán)節(jié),數(shù)據(jù)脫敏屬于安全控制的范疇。對互聯(lián)網(wǎng)公司、傳統(tǒng)行業(yè)來說,數(shù)據(jù)安全一直是極為重視和敏感的話題。

創(chuàng)新互聯(lián)是一家專業(yè)提供黔西南州企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站建設(shè)、成都做網(wǎng)站、html5、小程序制作等業(yè)務(wù)。10年已為黔西南州眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。
數(shù)據(jù)脫敏是指對某些敏感信息通過脫敏規(guī)則進(jìn)行數(shù)據(jù)的變形,實(shí)現(xiàn)敏感隱私數(shù)據(jù)的可靠保護(hù)。
涉及客戶安全數(shù)據(jù)或者一些商業(yè)性敏感數(shù)據(jù),如身份證號、手機(jī)號、卡號、客戶號等個人信息按照相關(guān)部門規(guī)定,都需要進(jìn)行數(shù)據(jù)脫敏。
今天來深入聊一下 Sharding-JDBC 如何對敏感數(shù)據(jù)脫敏,僅在持久層脫敏。
幾個重要概念
Sharding-JDBC 在底層進(jìn)行了脫敏的封裝,讓開發(fā)人員在無感知的情況下進(jìn)行數(shù)據(jù)脫敏,來看一下官方的詳情圖,如下:
下面針對上圖中涉及到的幾個名詞進(jìn)行詳細(xì)的解釋,在下文實(shí)戰(zhàn)中做個鋪墊。
1. 數(shù)據(jù)源配置
這個就是Datasource的配置。
2. 加密器配置
加密器就涉及到數(shù)據(jù)脫敏了,Sharding-JDBC 內(nèi)置了兩個加密器,如下:
- MD5Encryptor:MD5加密算法,一種不可逆的加密方式,通常用來對密碼進(jìn)行加密
- AESEncryptor:AES加密算法,一種可逆的加密方式,通常用來對回顯的字段加密,比如身份證、手機(jī)號碼
Sharding-JDBC還支持自定義加密器。
3. 脫敏表配置
用于告訴 Sharding-JDBC 數(shù)據(jù)表里哪個列用于存儲密文數(shù)據(jù)(cipherColumn)、哪個列用于存儲明文數(shù)據(jù)(plainColumn)以及用戶想使用哪個列進(jìn)行SQL編寫(logicColumn):
- logicColumn:邏輯列,這個和前文中邏輯表類似,用于實(shí)際的SQL編寫,比如數(shù)據(jù)庫中真實(shí)字段是cipher_pwd,但是在Sharding-JDBC配置時指定邏輯列的名稱為:pwd,那么在寫SQL的時候就要使用邏輯列pwd進(jìn)行查詢。
- cipherColumn:存儲密文數(shù)據(jù)的字段
- plainColumn:存儲明文數(shù)據(jù)的字段,一般不使用,不然脫敏也毫無意義
4. 查詢屬性的配置
當(dāng)?shù)讓訑?shù)據(jù)庫表里同時存儲了明文數(shù)據(jù)、密文數(shù)據(jù)后,該屬性開關(guān)用于決定是直接查詢數(shù)據(jù)庫表里的明文數(shù)據(jù)進(jìn)行返回,還是查詢密文數(shù)據(jù)通過Encrypt-JDBC解密后返回。
數(shù)據(jù)脫敏實(shí)戰(zhàn)
基本概念介紹完了,下面就使用Sharding-JDBC進(jìn)行數(shù)據(jù)脫敏。
這里就不再演示分庫分表了,直接用單庫進(jìn)行脫敏演示。
1. 新建表
筆者這里新建了一張用戶表t_user,如下:
CREATE TABLE `t_user` (
`user_id` bigint(20) NOT NULL COMMENT '用戶唯一ID',
`fullname` varchar(50) DEFAULT NULL COMMENT '名字',
`user_type` varchar(255) DEFAULT NULL COMMENT '類型',
`cipher_pwd` varchar(255) DEFAULT NULL COMMENT '密碼',
`mobile` varchar(100) DEFAULT NULL COMMENT '手機(jī)號',
`mobile_data` varchar(100) DEFAULT NULL COMMENT '手機(jī)號',
`id_card` varchar(60) DEFAULT NULL COMMENT '身份證',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2. 數(shù)據(jù)源配置
數(shù)據(jù)源這里使用單數(shù)據(jù)源,配置很簡單,上篇文章也演示過,配置如下:
spring:
# Sharding-JDBC的配置
shardingsphere:
datasource:
names: ds
# 數(shù)據(jù)源ds配置
ds:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
3. 加密器聲明
需要用到什么加密器需要事先在配置文件中聲明,這樣才能在字段中去引用,配置如下:
spring:
encrypt:
encryptors:
# md5加密算法-sharding-jdbc內(nèi)置的算法,這里名稱任意
encryptor_md5:
# 別名,這里一定要是MD5
type: MD5
# aes加密算法-sharding-jdbc內(nèi)置的算法,這里名稱任意
encryptor_aes:
# 別名,這里一定要是aes
type: aes
props:
# 設(shè)置秘鑰
aes.key.value: myjszl
上述總計(jì)配置了兩種Sharding-JDBC內(nèi)置的加密器,如下:
- encryptor_md5:MD5Encryptor加密器,這里的名稱可以任意,但是type這個屬性一定要是MD5
- encryptor_aes:AESEncryptor加密器,對稱加密算法,因此需要指定加密的秘鑰:aes.key.value
Sharding-JDBC指定規(guī)則如下:
#加解密器類型,可自定義或選擇內(nèi)置類型:MD5/AES
spring.shardingsphere.encrypt.encryptors..type=
#屬性配置, 注意:使用AES加密器,需要配置AES加密器的KEY屬性:aes.key.value
spring.shardingsphere.encrypt.encryptors..props. =
4. 對數(shù)據(jù)脫敏配置
下面針對三個字段進(jìn)行脫敏,如下:
- cipher_pwd:密碼使用不可逆的加密器MD5Encryptor
- id_card:身份證使用可逆的加密器AESEncryptor
- mobile:手機(jī)號使用可逆的加密器AESEncryptor
詳細(xì)的配置如下:
spring:
# Sharding-JDBC的配置
shardingsphere:
encrypt:
tables:
t_user:
columns:
# 邏輯列,sharding-jdbc中寫SQL需要用到的列
password:
# 存儲明文的字段
#plainColumn: password
# 存儲密文的字段
cipherColumn: cipher_pwd
# 指定加密器
encryptor: encryptor_md5
# 身份證號的邏輯列,使用aes這種可逆的加密算法
id_card:
cipherColumn: id_card
encryptor: encryptor_aes
# 手機(jī)號的邏輯列,使用aes這種可逆的加密算法
mobile:
cipherColumn: mobile
encryptor: encryptor_aes
Sharding-JDBC 指定的規(guī)則如下:
spring.shardingsphere.encrypt.tables..columns. .encryptor= #加密器名字
spring.shardingsphere.encrypt.tables..columns. .plainColumn= #存儲明文的字段
spring.shardingsphere.encrypt.tables..columns. .cipherColumn= #存儲密文的字段
注意:上述配置中的密碼這個字段,數(shù)據(jù)庫表中的真實(shí)字段是cipher_pwd,但是這里筆者指定的邏輯列是password,因此在寫SQL的時候,一定要寫password這個邏輯列,比如查詢的SQL,如下:
SELECT
password AS cipherPwd,
fullname,
user_type,
id_card AS id_card
FROM
t_user where user_id=?
現(xiàn)在向其中插入幾條數(shù)據(jù)看看效果,單元測試如下:
@Test
public void testInsertUser() {
for (int i = 0; i < 10; i++) {
User user = new User();
user.setFullName("不才陳某");
user.setCipherPwd("abc123");
user.setIdCard("320829198708012232");
user.setUserId((long)i);
user.setMobile("13852331509");
userMapper.insertUser(user);
}
}
數(shù)據(jù)如下:
可以看到數(shù)據(jù)持久化到數(shù)據(jù)庫中已經(jīng)脫敏了。
問題來了:那么查詢的效果出來的效果是什么?
試想一下,MD5加密器是不可逆的,AES加密器是可逆的,那么符合正常邏輯的狀態(tài)下就應(yīng)該是密碼這個字段查詢出來的還是密文(不可逆),身份證、手機(jī)號查詢出來的應(yīng)該是明文。
新建查詢的單元測試,如下:
@Test
public void testList() throws JsonProcessingException {
Listusers = userMapper.listAll();
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(users);
System.out.println(json);
}
結(jié)果如下:
很清楚了,一切都朝著我們的預(yù)料的方向發(fā)展~
限制條件
字段進(jìn)行脫敏后在寫SQL時有一些操作是不支持的,如下:
- 脫敏字段無法支持比較操作,如:大于小于、ORDER BY、BETWEEN、LIKE等。
- 脫敏字段無法支持計(jì)算操作,如:AVG、SUM以及計(jì)算表達(dá)式 。
原理
其實(shí)Sharding-JDBC數(shù)據(jù)脫敏原理很簡單,看一下官方給的一張圖:
1. 插入數(shù)據(jù)
加密器有一個公共的接口Encryptor,如下:
public interface Encryptor extends TypeBasedSPI {
/**
* Initialize.
*/
void init();
/**
* Encode.
*
* @param plaintext plaintext
* @return ciphertext
*/
String encrypt(Object plaintext);
/**
* Decode.
*
* @param ciphertext ciphertext
* @return plaintext
*/
Object decrypt(String ciphertext);
}
當(dāng)插入數(shù)據(jù)涉及到加密字段,即是定義的邏輯列,那么Sharding-JDBC內(nèi)部會將這條SQL改寫,將邏輯列替換成表的真實(shí)列,并且調(diào)用 encrypt(Object plaintext)方法將明文加密成密文后存儲進(jìn)去。
2. 更新數(shù)據(jù)
更新和插入數(shù)據(jù)一樣,同樣會將SQL改寫,調(diào)用encrypt(Object plaintext)方法將明文加密成密文后存儲進(jìn)去。
3. 查詢數(shù)據(jù)
查詢數(shù)據(jù)就比較復(fù)雜了,這里只討論默認(rèn)情況,則是使用加密列查詢,默認(rèn)配置如下:
spring.shardingsphere.props.query.with.cipher.column=true
查詢分為兩類,如下:
(1) where條件中不帶脫敏邏輯列
這種情況也就是在查詢結(jié)果集中涉及到脫敏的邏輯列,但是在查詢條件中不涉及,那么在返回結(jié)果的時候則會調(diào)用加密器的解密方法Object decrypt(String ciphertext)去將結(jié)果解密返回。
(2) where條件中帶脫敏邏輯列
這種情況就比較復(fù)雜了,where條件中涉及了脫敏邏輯列,那么在改寫SQL時會調(diào)用加密器的加密方法String encrypt(Object plaintext)將其加密成密文去查詢;
同樣返回結(jié)果集也會調(diào)用加密器的解密方法Object decrypt(String ciphertext)去將結(jié)果解密返回。
加密策略
Sharding-JDBC默認(rèn)提供了兩種內(nèi)置的加密器,但是實(shí)際開發(fā)中這兩種肯定是不夠用的,需要開發(fā)人員去自定義加密器應(yīng)該各種場景。
Sharding-JDBC提供了兩類加密策略接口,如下:
1. Encryptor
提供encrypt(), decrypt()兩種方法對需要脫敏的數(shù)據(jù)進(jìn)行加解密;在用戶進(jìn)行INSERT, DELETE, UPDATE時,ShardingSphere會按照用戶配置,對SQL進(jìn)行解析、改寫、路由,并會調(diào)用encrypt()將數(shù)據(jù)加密后存儲到數(shù)據(jù)庫, 而在SELECT時,則調(diào)用decrypt()方法將從數(shù)據(jù)庫中取出的脫敏數(shù)據(jù)進(jìn)行逆向解密,最終將原始數(shù)據(jù)返回給用戶。
接口如下:
public interface Encryptor extends TypeBasedSPI {
void init();
String encrypt(Object plaintext);
Object decrypt(String ciphertext);
}
2. QueryAssistedEncryptor
相比較于第一種脫敏方案,該方案更為安全和復(fù)雜。它的理念是:即使是相同的數(shù)據(jù),如兩個用戶的密碼相同,它們在數(shù)據(jù)庫里存儲的脫敏數(shù)據(jù)也應(yīng)當(dāng)是不一樣的。這種理念更有利于保護(hù)用戶信息,防止撞庫成功。
它提供三種函數(shù)進(jìn)行實(shí)現(xiàn),分別是encrypt(), decrypt(), queryAssistedEncrypt()。在encrypt()階段,用戶通過設(shè)置某個變動種子,例如時間戳。針對原始數(shù)據(jù)+變動種子組合的內(nèi)容進(jìn)行加密,就能保證即使原始數(shù)據(jù)相同,也因?yàn)橛凶儎臃N子的存在,致使加密后的脫敏數(shù)據(jù)是不一樣的。在decrypt()可依據(jù)之前規(guī)定的加密算法,利用種子數(shù)據(jù)進(jìn)行解密。
雖然這種方式確實(shí)可以增加數(shù)據(jù)的保密性,但是另一個問題卻隨之出現(xiàn):相同的數(shù)據(jù)在數(shù)據(jù)庫里存儲的內(nèi)容是不一樣的,那么當(dāng)用戶按照這個加密列進(jìn)行等值查詢(SELECT FROM table WHERE encryptedColumnn = ?)時會發(fā)現(xiàn)無法將所有相同的原始數(shù)據(jù)查詢出來。
為此,我們提出了輔助查詢列的概念。該輔助查詢列通過queryAssistedEncrypt()生成,與decrypt()不同的是,該方法通過對原始數(shù)據(jù)進(jìn)行另一種方式的加密,但是針對原始數(shù)據(jù)相同的數(shù)據(jù),這種加密方式產(chǎn)生的加密數(shù)據(jù)是一致的。
將queryAssistedEncrypt()后的數(shù)據(jù)存儲到數(shù)據(jù)中用于輔助查詢真實(shí)數(shù)據(jù)。因此,數(shù)據(jù)庫表中多出這一個輔助查詢列。
由于queryAssistedEncrypt()和encrypt()產(chǎn)生不同加密數(shù)據(jù)進(jìn)行存儲,而decrypt()可逆,queryAssistedEncrypt()不可逆。在查詢原始數(shù)據(jù)的時候,會自動對SQL進(jìn)行解析、改寫、路由,利用輔助查詢列進(jìn)行 WHERE條件的查詢,卻利用 decrypt()對encrypt()加密后的數(shù)據(jù)進(jìn)行解密,并將原始數(shù)據(jù)返回給用戶。這一切都是對用戶透明化的。
簡單概括一下:
- QueryAssistedEncryptor更加安全,加了一個變動因子一起加密,這樣即使內(nèi)容一樣加密后的密文也是不同的
- 為了查詢方便,提供了一個輔助查詢列,這個輔助查詢列中的數(shù)據(jù)不帶變動因子,直接明文加密的,可以根據(jù)輔助查詢列查詢
- 這一切的操作都是透明的,開發(fā)人員無須關(guān)心,只需要按照給定的規(guī)則配置
接口如下:
public interface QueryAssistedEncryptor extends Encryptor {
String queryAssistedEncrypt(String plaintext);
}
QueryAssistedEncryptor這類加密策略并無內(nèi)置的加密器,需要開發(fā)人員自定義實(shí)現(xiàn)。
如何自定義加密器
上文介紹到了Sharding-JDBC支持的兩種加密策略,肯定都是要實(shí)現(xiàn)一下,下面將會針對兩種策略去介紹一下如何自定義。
1. Encryptor 自定義實(shí)現(xiàn)
自定義很簡單,直接實(shí)現(xiàn)Encryptor 接口即可,重寫其中的加密、解密方法。
下面自定義一個SHA256加密算法器,這是一種不可逆的算法,如下:
/**
* @author 不才陳某 公眾號:碼猿技術(shù)專欄
* 自定義的加密解密算法,基于sha256
*/
@Data
public class Sha256HexEncryptor implements Encryptor {
/**
* 別名,配置時需要
*/
public final static String ALGORITHM_NAME="SHA256";
private Properties properties = new Properties();
@Override
public void init() {
}
/**
* 加密
* INSERT, DELETE, UPDATE時會調(diào)用該方法進(jìn)行加密存儲到數(shù)據(jù)庫中
* @param plaintext 明文
* @return 加密后的密文
*/
@Override
public String encrypt(final Object plaintext) {
if (null == plaintext) {
return null;
}
return DigestUtils.sha256Hex(String.valueOf(plaintext));
}
/**
* 解密
* 在SELECT 查詢會調(diào)用該方法進(jìn)行解密
* @param ciphertext 密文
* @return 由于sha256是一種不可逆的算法,因此直接返回密文
*/
@Override
public String decrypt(final String ciphertext) {
return ciphertext;
}
/**
* 別名,在配置中指定的名稱
*/
@Override
public String getType() {
return Sha256HexEncryptor.ALGORITHM_NAME;
}
}
加密解密的過程和MD5Encryptor加密器類似,不再詳細(xì)介紹了,很容易理解。
由于是使用SPI的方式,因此還需要在resource/META-INF/services目錄中新建一個org.apache.shardingsphere.encrypt.strategy.spi.Encryptor文件,內(nèi)容如下:
com.java.family.shardingjdbc003.encryptor.Sha256HexEncryptor
好了,現(xiàn)在這個SHA256加密器就已經(jīng)定義好了,可以在配置文件中配置了。
現(xiàn)在使用自定義SHA256加密器對密碼這個列進(jìn)行加密,分為如下步驟:
(1) 聲明加密器
聲明很簡單,配置如下:
spring:
# Sharding-JDBC的配置
shardingsphere:
encrypt:
encryptors:
# sha256加密算法,自定義的
encryptor_sha256:
type: SHA256
(2) 邏輯列配置加密器
只需要將加密器的名字改成上面聲明的encryptor_sha256即可,配置如下:
spring:
# Sharding-JDBC的配置
shardingsphere:
encrypt:
tables:
t_user:
columns:
# 邏輯列,sharding-jdbc中寫SQL需要用到的列
password:
# 存儲明文的字段
#plainColumn: password
# 存儲密文的字段
cipherColumn: cipher_pwd
# 指定加密器
encryptor: encryptor_sha256
至此,配置成功了,自己去演示看一下吧,這里就不再細(xì)說了。
2. QueryAssistedEncryptor 自定義實(shí)現(xiàn)
下面通過Base64加密算法自定義實(shí)現(xiàn)一個QueryAssistedEncryptor加密器,如下:
/**
* @author 不才陳某 公眾號:碼猿技術(shù)專欄
* 自定義QueryAssistedEncryptor加密器
*/
@Data
public class Base64AssistedEncryptor implements QueryAssistedEncryptor {
/**
* 別名,配置時需要
*/
public final static String ALGORITHM_NAME="Base64_Assisted";
private Properties properties = new Properties();
/**
* 輔助查詢列的加密方法
*/
@Override
public String queryAssistedEncrypt(String plaintext) {
if (null == plaintext) {
return null;
}
return Base64.encode(plaintext);
}
@Override
public void init() {
}
/**
* 加密方法
* 使用時間戳作為變動因子
*/
@Override
public String encrypt(final Object plaintext) {
if (null == plaintext) {
return null;
}
//獲取時間戳作為變動因子
String randomFactor =String.valueOf( new Date().getTime());
return Base64.encode(plaintext+"_"+randomFactor);
}
/**
* 解密方法
* Base64是一個可逆的加密算法,因此可以對密文進(jìn)行解密并且剔除變動因子則為明文
*/
@SneakyThrows
@Override
public Object decrypt(final String ciphertext) {
if (null == ciphertext) {
return null;
}
return new String(Base64.decode(ciphertext),"UTF-8").split("_")[0];
}
@Override
public String getType() {
return ALGORITHM_NAME;
}
}
需要注意以下兩點(diǎn):
- queryAssistedEncrypt():該方法在插入、更新邏輯列設(shè)置輔助查詢列值、邏輯列作為where查詢條件時會被調(diào)用對輔助查詢列加密
- decrypt():這里的Base64是可逆的加密算法,因此只需要對其解密,并且剔除變動因子則為明文
同樣的也需要在resource/META-INF/services目錄中新建一個org.apache.shardingsphere.encrypt.strategy.spi.Encryptor文件,內(nèi)容如下:
com.java.family.shardingjdbc003.encryptor.Base64AssistedEncryptor
配置也很簡單,同樣分為兩步,如下:
(1) 聲明加密器
配置如下:
spring:
# Sharding-JDBC的配置
shardingsphere:
encrypt:
encryptors:
# Base64加密算法,自定義的
encryptor_base64_assisted:
type: Base64_Assisted
(2) 邏輯列配置加密器
只需要將加密器的名字改成上面聲明的encryptor_base64_assisted即可,配置如下:
spring:
# Sharding-JDBC的配置
shardingsphere:
encrypt:
tables:
t_user:
columns:
# 邏輯列,sharding-jdbc中寫SQL需要用到的列
mobile:
# 密文存儲的列
cipherColumn: mobile
# 輔助查詢列,表中真實(shí)的字段名
assistedQueryColumn: mobile_data
encryptor: encryptor_base64_assisted
唯一不同的就是多了一個assistedQueryColumn輔助查詢列的配置。
好了,上述配置好了以后就可以進(jìn)行單元測試了,插入數(shù)據(jù)結(jié)果:
可以看到mobile這個字段的值都是不同的,但是mobile_data這個輔助查詢列都是相同的,因?yàn)檩o助查詢列并未使用變動因子進(jìn)行加密。
關(guān)于查詢?nèi)绻婕暗絤obile的條件查詢,那么將會調(diào)用queryAssistedEncrypt()方法加密后根據(jù)輔助查詢mobile_data列進(jìn)行查詢,SQL如下圖:
分享名稱:聊聊Sharding-JDBC數(shù)據(jù)脫敏
網(wǎng)站路徑:http://m.fisionsoft.com.cn/article/cohpdcj.html


咨詢
建站咨詢
