ShardingSphere4.1.1:Sharding-JDBC數據加密及SPI加密策略實現


0、脫敏規則

1、環境構建

1.1、創建一個 Spring Boot 項目,引入依賴如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <groupId>cn.zwqh</groupId>
        <artifactId>sharding-sphere-4.1.1</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.zwqh</groupId>
    <artifactId>sharding-sphere-demo-8</artifactId>
    <version>${parent.version}</version>

    <packaging>jar</packaging>
    <name>sharding-sphere-demo-8</name>
    <description>Demo project for Spring Boot</description>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>${sharding-sphere.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>cn.zwqh.shardingspheredemo8.ShardingSphereDemo8Application</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project> 

1.2、測試數據庫 ds1

CREATE TABLE `t_user` (
  `user_id` int NOT NULL COMMENT '用戶id',
  `user_name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用戶名稱',
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密碼明文',
  `password_encrypt` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密碼密文',
  `password_assisted` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '輔助查詢列',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 

1.3、實體類

@Data
public class UserEntity {

    private Integer userId;

    private String userName;

    private String password;

    private String passwordEncrypt;

    private String passwordAssisted;
} 

1.4、Mapper

@Mapper
public interface UserMapper {

    @Insert("insert into t_user(user_id,user_name,password) values(#{userId},#{userName},#{password})")
    void insertUser(UserEntity userEntity);

    @Select("select * from t_user where user_name=#{userName} and password=#{password}")
    @Results({
            @Result(column = "user_id", property = "userId"),
            @Result(column = "user_name", property = "userName"),
            @Result(column = "password", property = "password"),
            @Result(column = "password_assisted", property = "passwordAssisted")
    })
    List<UserEntity> getUserInfo(@Param("userName") String userName, @Param("password") String password);
} 

1.5、測試類

@Slf4j
@SpringBootTest
class ShardingSphereDemo8ApplicationTests {

    @Resource
    private UserMapper userMapper;

    @Test
    void insertUser() {
        UserEntity userEntity = new UserEntity();
        userEntity.setUserId(19);
        userEntity.setUserName("user19");
        userEntity.setPassword("123456");
        userMapper.insertUser(userEntity);
    }

    @Test
    void getUserInfo() {
        List<UserEntity> userEntityList = userMapper.getUserInfo("user19", "123456");
        log.info(userEntityList.toString());
    }

} 

2、默認加密算法

2.1、AES

配置文件

# 應用名稱
spring.application.name=sharding-sphere-demo-8
spring.shardingsphere.datasource.name=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=123456
spring.shardingsphere.datasource.ds.max-total=100
# 采用AES對稱加密策略
spring.shardingsphere.encrypt.encryptors.encryptor_aes.type=aes
spring.shardingsphere.encrypt.encryptors.encryptor_aes.props.aes.key.value=123456
# password為邏輯列,password為數據表明文列,password_encrypt為數據表密文列
spring.shardingsphere.encrypt.tables.t_user.columns.password.plainColumn=password
spring.shardingsphere.encrypt.tables.t_user.columns.password.cipherColumn=password_encrypt
spring.shardingsphere.encrypt.tables.t_user.columns.password.encryptor=encryptor_aes
spring.shardingsphere.props.sql.show=true
# 查詢是否使用密文列
spring.shardingsphere.props.query.with.cipher.column=true 

測試結果

1、設置了明文列和密文列,運行成功,新增時邏輯列會改寫成明文列和密文列

2、僅設置明文列,運行直接報錯,所以必須設置加密列

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'encryptDataSource' defined in class path resource [org/apache/shardingsphere/shardingjdbc/spring/boot/SpringBootConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'encryptDataSource' threw exception; nested exception is java.lang.IllegalArgumentException: Invalid encrypt column configurations in EncryptTableRuleConfigurations. 

3、僅設置密文列,運行成功,明文會進行加密,數據庫實際插入到密文列

4、設置了明文列和密文列, spring.shardingsphere.props.query.with.cipher.column 為false時,查詢通過明文列執行,返回數據為明文列

5、設置了明文列和密文列, spring.shardingsphere.props.query.with.cipher.column 為true時,查詢通過密文列查詢,返回數據為明文

6、僅設置密文列, spring.shardingsphere.props.query.with.cipher.column 為false時,查詢默認通過密文列查詢,但入參未進行自動加密,所以不能查到數據

7、僅設置密文列, spring.shardingsphere.props.query.with.cipher.column 為true時,查詢通過密文列查詢,返回數據為明文

2.2、MD5

配置文件

# 應用名稱
spring.application.name=sharding-sphere-demo-8
spring.shardingsphere.datasource.name=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=123456
spring.shardingsphere.datasource.ds.max-total=100
# 采用MD5加密策略
spring.shardingsphere.encrypt.encryptors.encryptor_md5.type=MD5
# password為邏輯列,password為數據表明文列,password_encrypt為數據表密文列
spring.shardingsphere.encrypt.tables.t_user.columns.password.plainColumn=password
spring.shardingsphere.encrypt.tables.t_user.columns.password.cipherColumn=password_encrypt
spring.shardingsphere.encrypt.tables.t_user.columns.password.encryptor=encryptor_md5
spring.shardingsphere.props.sql.show=true
# 查詢是否使用密文列
spring.shardingsphere.props.query.with.cipher.column=true 

測試結果

1、新增時,可以看到加密后的數據和AES的有所區別

2、查詢時,spring.shardingsphere.props.query.with.cipher.column為true時,通過密文列查詢,由於MD5加密是非對稱的,所以返回的是密文數據

3、查詢時,spring.shardingsphere.props.query.with.cipher.column為false時,通過明文列查詢,返回明文數據

3、SPI自定義加密算法

3.1、SPI 配置

在resources/META-INF/services目錄下新增配置

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

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

org.apache.shardingsphere.encrypt.strategy.impl.AESEncryptor
org.apache.shardingsphere.encrypt.strategy.impl.MD5Encryptor
cn.zwqh.shardingspheredemo8.encryptor.Sha256Encryptor
cn.zwqh.shardingspheredemo8.encryptor.Sha256RandomEncryptor 

3.2、實現Encryptor接口

創建 Sha256Encryptor 類

@Getter
@Setter
public class Sha256Encryptor implements Encryptor {

    private Properties properties = new Properties();

    @Override
    public void init() {

    }

    @Override
    public String encrypt(Object plaintext) {
        if (null == plaintext) {
            return null;
        }
        return DigestUtils.sha256Hex(String.valueOf(plaintext));
    }

    @Override
    public Object decrypt(String ciphertext) {
        return ciphertext;
    }

    @Override
    public String getType() {
        return "SHA256";
    }
} 

修改配置文件

# 應用名稱
spring.application.name=sharding-sphere-demo-8
spring.shardingsphere.datasource.name=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=123456
spring.shardingsphere.datasource.ds.max-total=100
# 采用自定義策略 SHA256
spring.shardingsphere.encrypt.encryptors.encryptor_sha256.type=SHA256
# password為邏輯列,password為數據表明文列,password_encrypt為數據表密文列
spring.shardingsphere.encrypt.tables.t_user.columns.password.plainColumn=password
spring.shardingsphere.encrypt.tables.t_user.columns.password.cipherColumn=password_encrypt
spring.shardingsphere.encrypt.tables.t_user.columns.password.encryptor=encryptor_sha256
spring.shardingsphere.props.sql.show=true
# 查詢是否使用密文列
spring.shardingsphere.props.query.with.cipher.column=true 

測試結果

1、新增時,可以看到加密后的數據和AES的有所區別,說明自定義加密策略使用成功

2、查詢時,spring.shardingsphere.props.query.with.cipher.column為true時,通過密文列查詢,由於SHA256類似MD5加密,所以返回的是密文數據

3、查詢時,spring.shardingsphere.props.query.with.cipher.column為false時,通過明文列查詢,返回明文數據

3.3、實現QueryAssistedEncryptor接口

創建 Sha256RandomEncryptor 類

@Getter
@Setter
public class Sha256RandomEncryptor implements QueryAssistedEncryptor {

    private Properties properties = new Properties();

    @Override
    public String queryAssistedEncrypt(String plaintext) {
        if (null == plaintext) {
            return null;
        }
        // 原始字符串
        return DigestUtils.sha256Hex(String.valueOf(plaintext));
    }

    @Override
    public void init() {

    }

    @Override
    public String encrypt(Object plaintext) {
        if (null == plaintext) {
            return null;
        }
        // 原始字符串+變動因子(如時間戳)
        plaintext = plaintext.toString() + LocalDateTime.now().toString();
        return DigestUtils.sha256Hex(String.valueOf(plaintext));
    }

    @Override
    public Object decrypt(String ciphertext) {
        return ciphertext;
    }

    @Override
    public String getType() {
        return "SHA256_RANDOM";
    }
} 

修改配置文件

# 應用名稱
spring.application.name=sharding-sphere-demo-8
spring.shardingsphere.datasource.name=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=123456
spring.shardingsphere.datasource.ds.max-total=100
# 采用自定義策略 SHA256_RANDOM
spring.shardingsphere.encrypt.encryptors.encryptor_sha256_random.type=SHA256_RANDOM
# password為邏輯列,password為數據表明文列,password_encrypt為數據表密文列,password_assisted輔助查詢列
spring.shardingsphere.encrypt.tables.t_user.columns.password.plainColumn=password
spring.shardingsphere.encrypt.tables.t_user.columns.password.cipherColumn=password_encrypt
spring.shardingsphere.encrypt.tables.t_user.columns.password.assistedQueryColumn=password_assisted
spring.shardingsphere.encrypt.tables.t_user.columns.password.encryptor=encryptor_sha256_random
spring.shardingsphere.props.sql.show=true
# 查詢是否使用密文列
spring.shardingsphere.props.query.with.cipher.column=true 

測試結果

1、新增兩條用戶數據,密碼一致,可以看到密文列的數據是不一致的,輔助列的數據一致,這樣可以更好的保護數據安全

2、查詢時,spring.shardingsphere.props.query.with.cipher.column為true時,通過輔助查詢列查詢,而返回的數據為密文列

3、查詢時,spring.shardingsphere.props.query.with.cipher.column為false時,通過明文列查詢,而返回的數據為明文

小結

1、數據加密默認算法支持 AES 和 MD5 兩種,AES 為對稱加密,MD5 為非對稱加密;

2、可以通過 SPI 自定義實現加密策略;

3、根據業務安全需求選擇合適的加密算法以及配置。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM