聊聊 Sharding-JDBC 数据脱敏(四)

love374
发布于 2022-7-8 17:27
浏览
0收藏

 

2.  更新数据
更新和插入数据一样,同样会将SQL改写,调用encrypt(Object plaintext)方法将明文加密成密文后存储进去。

 

3.  查询数据
查询数据就比较复杂了,这里只讨论默认情况,则是使用加密列查询,默认配置如下:

spring.shardingsphere.props.query.with.cipher.column=true

 

查询分为两类,如下:

1.where条件中不带脱敏逻辑列

这种情况也就是在查询结果集中涉及到脱敏的逻辑列,但是在查询条件中不涉及,那么在返回结果的时候则会调用加密器的解密方法Object decrypt(String ciphertext)去将结果解密返回

 

2.where条件中带脱敏逻辑列

这种情况就比较复杂了,where条件中涉及了脱敏逻辑列,那么在改写SQL时会调用加密器的加密方法String encrypt(Object plaintext)将其加密成密文去查询;

 

同样返回结果集也会调用加密器的解密方法Object decrypt(String ciphertext)去将结果解密返回

 

加密策略
Sharding-JDBC默认提供了两种内置的加密器,但是实际开发中这两种肯定是不够用的,需要开发人员去自定义加密器应该各种场景。

 

Sharding-JDBC提供了两类加密策略接口,如下:

 

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

接口如下:

public interface Encryptor extends TypeBasedSPI {
    void init();
    String encrypt(Object plaintext);
    Object decrypt(String ciphertext);
}

 

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

 

它提供三种函数进行实现,分别是encrypt(), decrypt(), queryAssistedEncrypt()。在encrypt()阶段,用户通过设置某个变动种子,例如时间戳。针对原始数据+变动种子组合的内容进行加密,就能保证即使原始数据相同,也因为有变动种子的存在,致使加密后的脱敏数据是不一样的。在decrypt()可依据之前规定的加密算法,利用种子数据进行解密。

 

虽然这种方式确实可以增加数据的保密性,但是另一个问题却随之出现:相同的数据在数据库里存储的内容是不一样的,那么当用户按照这个加密列进行等值查询(SELECT FROM table WHERE encryptedColumnn = ?)时会发现无法将所有相同的原始数据查询出来。

 

为此,我们提出了辅助查询列的概念。该辅助查询列通过queryAssistedEncrypt()生成,与decrypt()不同的是,该方法通过对原始数据进行另一种方式的加密,但是针对原始数据相同的数据,这种加密方式产生的加密数据是一致的。

 

将queryAssistedEncrypt()后的数据存储到数据中用于辅助查询真实数据。因此,数据库表中多出这一个辅助查询列。

 

由于queryAssistedEncrypt()和encrypt()产生不同加密数据进行存储,而decrypt()可逆,queryAssistedEncrypt()不可逆。在查询原始数据的时候,会自动对SQL进行解析、改写、路由,利用辅助查询列进行 WHERE条件的查询,却利用 decrypt()对encrypt()加密后的数据进行解密,并将原始数据返回给用户。这一切都是对用户透明化的。

“上文部分内容摘抄自官方文档”
简单概括一下:

  1. QueryAssistedEncryptor更加安全,加了一个变动因子一起加密,这样即使内容一样加密后的密文也是不同的
  2. 为了查询方便,提供了一个辅助查询列,这个辅助查询列中的数据不带变动因子,直接明文加密的,可以根据辅助查询列查询
  3. 这一切的操作都是透明的,开发人员无须关心,只需要按照给定的规则配置


接口如下:

public interface QueryAssistedEncryptor extends Encryptor {
    String queryAssistedEncrypt(String plaintext);
}

“QueryAssistedEncryptor这类加密策略并无内置的加密器,需要开发人员自定义实现”


如何自定义加密器
上文介绍到了Sharding-JDBC支持的两种加密策略,肯定都是要实现一下,下面将会针对两种策略去介绍一下如何自定义。

前提:由于Sharding-JDBC中的加密器是使用SPI方式让开发人员扩展的,因此你还要了解一下SPI,有不清楚的可以看我之前的文章:聊聊 Java SPI 机制

1. Encryptor 自定义实现
自定义很简单,直接实现Encryptor 接口即可,重写其中的加密、解密方法。

下面自定义一个SHA256加密算法器,这是一种不可逆的算法,如下:

/**
 * @author 不才陈某 公众号:码猿技术专栏
 * 自定义的加密解密算法,基于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时会调用该方法进行加密存储到数据库中
     * @param plaintext 明文
     * @return  加密后的密文
     */
    @Override
    public String encrypt(final Object plaintext) {
        if (null == plaintext) {
            return null;
        }
        return DigestUtils.sha256Hex(String.valueOf(plaintext));
    }

    /**
     * 解密
     * 在SELECT 查询会调用该方法进行解密
     * @param ciphertext 密文
     * @return 由于sha256是一种不可逆的算法,因此直接返回密文
     */
    @Override
    public String decrypt(final String ciphertext) {
        return ciphertext;
    }

    /**
     * 别名,在配置中指定的名称
     */
    @Override
    public String getType() {
        return Sha256HexEncryptor.ALGORITHM_NAME;
    }
}

 

加密解密的过程和MD5Encryptor加密器类似,不再详细介绍了,很容易理解。

由于是使用SPI的方式,因此还需要在resource/META-INF/services目录中新建一个org.apache.shardingsphere.encrypt.strategy.spi.Encryptor文件,内容如下:

com.java.family.shardingjdbc003.encryptor.Sha256HexEncryptor

好了,现在这个SHA256加密器就已经定义好了,可以在配置文件中配置了。

 

文章转自公众号:码猿技术专栏

标签
已于2022-7-8 17:27:24修改
收藏
回复
举报
回复
    相关推荐