ShardingSphere应用专题--4.1.1版本--Sharding-JDBC 字段加密之自定义加密策略(十一)

前言

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应用专题–4.1.1版本–Sharding-JDBC 字段加密之新业务加密(九)
    - ShardingSphere应用专题–4.1.1版本–Sharding-JDBC 字段加密之已上线业务加密(十)

中间件脱敏服务优势

  1. 自动化&透明化数据脱敏过程,用户无需关注脱敏中间实现细节。
  2. 提供多种内置、第三方(AKS)的脱敏策略,用户仅需简单配置即可使用。
  3. 提供脱敏策略API接口,用户可实现接口,从而使用自定义脱敏策略进行数据脱敏。
  4. 支持切换不同的脱敏策略。
  5. 针对已上线业务,可实现明文数据与密文数据同步存储,并通过配置决定使用明文列还是密文列进行查询。可实现在不改变业务查询SQL前提下,已上线系统对加密前后数据进行安全、透明化迁移。

适用场景说明

  1. 用户项目使用Java语言进行编程。
  2. 后端数据库为MySQL、Oracle、PostgreSQL、SQLServer。
  3. 用户需要对数据库表中某个或多个列进行脱敏(数据加密&解密)。
  4. 兼容所有常用SQL。

限制条件

  1. 用户需要自行处理数据库中原始的存量数据、洗数。
  2. 使用脱敏功能+分库分表功能,部分特殊SQL不支持,请参考SQL使用规范。
  3. 脱敏字段无法支持比较操作,如:大于小于、ORDER BY、BETWEEN、LIKE等。
  4. 脱敏字段无法支持计算操作,如:AVG、SUM以及计算表达式 。

加密策略解析

ShardingSphere提供了两种加密策略用于数据脱敏,该两种策略分别对应ShardingSphere的两种加解密的接口,即ShardingEncryptor和ShardingQueryAssistedEncryptor。

一方面,ShardingSphere为用户提供了内置的加解密实现类,用户只需进行配置即可使用;另一方面,为了满足用户不同场景的需求,我们还开放了相关加解密接口,用户可依据该两种类型的接口提供具体实现类。再进行简单配置,即可让ShardingSphere调用用户自定义的加解密方案进行数据脱敏。

ShardingEncryptor

该解决方案通过提供encrypt(), decrypt()两种方法对需要脱敏的数据进行加解密。在用户进行INSERT, DELETE, UPDATE时,ShardingSphere会按照用户配置,对SQL进行解析、改写、路由,并会调用encrypt()将数据加密后存储到数据库, 而在SELECT时,则调用decrypt()方法将从数据库中取出的脱敏数据进行逆向解密,最终将原始数据返回给用户。

当前,ShardingSphere针对这种类型的脱敏解决方案提供了两种具体实现类,分别是MD5(不可逆),AES(可逆),用户只需配置即可使用这两种内置的方案。

ShardingQueryAssistedEncryptor

相比较于第一种脱敏方案,该方案更为安全和复杂。它的理念是:即使是相同的数据,如两个用户的密码相同,它们在数据库里存储的脱敏数据也应当是不一样的。这种理念更有利于保护用户信息,防止撞库成功。

它提供三种函数进行实现,分别是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

  • 父接口AInterface支持SPI扩展机制
  • 在/resources/META-INF/services定义com.a.b.AInterface的文件(没有后缀),内容是com.c.d.BImplements

代码实现自定义加密

自定义模块官方给的SPI扩展接口为org.apache.shardingsphere.encrypt.strategy.spi.Encryptor

(1)子类实现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]

(2)按照SPI扩展的规定,创建配置文件

在这里插入图片描述
文件内容为(1)中子类的【全限定类名】

com.example.sharding.customize.encrypt.Sha256Encryptor
(3)配置文件启用自定义加密
#打印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

代码测试

ShardingSphere应用专题--4.1.1版本--Sharding-JDBC 字段加密之自定义加密策略(十一)_第1张图片
日志上可以看到,自定义的加密策略被使用了

你可能感兴趣的:(中间件,集群/分布式,MySQL,java,mysql,sharding,shardingsphere,数据加密)