1.基础的环境介绍请移步ShardingSphere应用专题–4.1.1版本–sharding jdbc环境搭建(四)
你可以同时打开两个页面,避免因查找原始配置上下翻动。
2.ShardingSphere官方文档更新不及时,很容易踩坑。贴出的4.x版本文档实际是4.0.1版本的,如果你准备使用该版本可以参考官方文档。本文使用的是此时最新的正式版本4.1.1版本,配置与官方文档配置不同。事实上,源码中有非常详细的版本配置文档,本文也是参考4.1.1 tag的源码配置。
3.ShardingSphere各版本差异很大,甚至核心依赖的包名都不一样,使用时,一定要确认使用哪个版本,目前调研的结果:3.x、4.0.1、4.1.1、5.0.0-alpha都存在很大的配置差异
4.关于字段加密的场景参阅:
ShardingSphere提供了两种加密策略用于数据脱敏,该两种策略分别对应ShardingSphere的两种加解密的接口,即ShardingEncryptor和ShardingQueryAssistedEncryptor。
一方面,ShardingSphere为用户提供了内置的加解密实现类,用户只需进行配置即可使用;另一方面,为了满足用户不同场景的需求,我们还开放了相关加解密接口,用户可依据该两种类型的接口提供具体实现类。再进行简单配置,即可让ShardingSphere调用用户自定义的加解密方案进行数据脱敏。
该解决方案通过提供encrypt()
, decrypt()
两种方法对需要脱敏的数据进行加解密。在用户进行INSERT
, DELETE
, UPDATE
时,ShardingSphere会按照用户配置,对SQL进行解析、改写、路由,并会调用encrypt()
将数据加密后存储到数据库, 而在SELECT
时,则调用decrypt()
方法将从数据库中取出的脱敏数据进行逆向解密,最终将原始数据返回给用户。
当前,ShardingSphere针对这种类型的脱敏解决方案提供了两种具体实现类,分别是MD5(不可逆),AES(可逆),用户只需配置即可使用这两种内置的方案。
相比较于第一种脱敏方案,该方案更为安全和复杂。它的理念是:即使是相同的数据,如两个用户的密码相同,它们在数据库里存储的脱敏数据也应当是不一样的。这种理念更有利于保护用户信息,防止撞库成功。
它提供三种函数进行实现,分别是encrypt()
, decrypt()
, queryAssistedEncrypt()
。在encrypt()
阶段,用户通过设置某个变动种子,例如时间戳。针对原始数据+变动种子组合的内容进行加密,就能保证即使原始数据相同,也因为有变动种子的存在,致使加密后的脱敏数据是不一样的。在decrypt()
可依据之前规定的加密算法,利用种子数据进行解密。
虽然这种方式确实可以增加数据的保密性,但是另一个问题却随之出现:相同的数据在数据库里存储的内容是不一样的,那么当用户按照这个加密列进行等值查询(SELECT FROM table WHERE encryptedColumnn = ?
)时会发现无法将所有相同的原始数据查询出来。为此,我们提出了辅助查询列的概念。该辅助查询列通过queryAssistedEncrypt()
生成,与decrypt()
不同的是,该方法通过对原始数据进行另一种方式的加密,但是针对原始数据相同的数据,这种加密方式产生的加密数据是一致的。将queryAssistedEncrypt()
后的数据存储到数据中用于辅助查询真实数据。因此,数据库表中多出这一个辅助查询列。
由于queryAssistedEncrypt()
和encrypt()
产生不同加密数据进行存储,而decrypt()
可逆,queryAssistedEncrypt()
不可逆。 在查询原始数据的时候,我们会自动对SQL进行解析、改写、路由,利用辅助查询列进行
WHERE
条件的查询,却利用 decrypt()
对encrypt()
加密后的数据进行解密,并将原始数据返回给用户。这一切都是对用户透明化的。
当前,ShardingSphere针对这种类型的脱敏解决方案并没有提供具体实现类,却将该理念抽象成接口,提供给用户自行实现。ShardingSphere将调用用户提供的该方案的具体实现类进行数据脱敏。
在Apache ShardingSphere中,很多功能实现类的加载方式是通过SPI注入的方式完成的。 Service Provider Interface (SPI)是一种为了被第三方实现或扩展的API,它可以用于实现框架扩展或组件替换。具体官方预留的SPI扩展的接口参阅:官方文档-SPI
SPI简单说,就是定义了一种扩展机制,按照SPI的规定,在/resources/根目录下创建/META-INF/services,创建文件,文件名为你要扩展的接口的【全限定类名】,然后文件内部填写你的子类实现的【全限定类名】。这样子类就可以被SPI机制加载到内存中了
比如有一个接口的【全限定类名】为 com.a.b.AInterface,他的子类的【全限定类名】为com.c.d.BImplements
自定义模块官方给的SPI扩展接口为org.apache.shardingsphere.encrypt.strategy.spi.Encryptor
package com.example.sharding.customize.encrypt;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.shardingsphere.encrypt.strategy.spi.Encryptor;
import java.util.Properties;
@NoArgsConstructor
@Data
@Slf4j
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;
}
log.info("Sha256Encryptor encrypt,value:{}", plaintext);
return DigestUtils.sha256Hex(String.valueOf(plaintext));
}
@Override
public Object decrypt(final String ciphertext) {
log.info("Sha256Encryptor decrypt,value:{}", ciphertext);
return ciphertext;
}
@Override
public String getType() {
return "sha256";
}
@Override
public void setProperties(Properties properties) {
if (properties == null) {
return;
}
this.properties = properties;
}
}
加密类型定义为[sha256]
com.example.sharding.customize.encrypt.Sha256Encryptor
#打印sql
spring.shardingsphere.props.sql.show=true
#设置单次请求可适用的最大线程数,以决定是线程限制还是内存限制。增大该参数可提高数据库元数据加载速度(默认为1)
spring.shardingsphere.props.max.connections.size.per.query=3
spring.shardingsphere.datasource.names=master
spring.shardingsphere.datasource.master.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.master.jdbc-url=jdbc:mysql://localhost:4406/mydb?characterEncoding=utf-8
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=111
spring.shardingsphere.encrypt.tables.bill.columns.bill_name.cipherColumn=bill_name_cipher
spring.shardingsphere.encrypt.tables.bill.columns.bill_name.encryptor=encryptor_customize
spring.shardingsphere.encrypt.encryptors.encryptor_customize.type=sha256
spring.shardingsphere.encrypt.encryptors.encryptor_customize.props.aes.key.value