本文介绍如何实现全加密云数据库功能。

前提条件

  • RDS PostgreSQL服务端
  • 本地客户端
    • 已具备Java 1.8+的开发环境。
    • 已下载libencdb.jar依赖包。
    • 已生成用户主密钥。
      说明
      • 用户主密钥是您访问加密数据的根凭据,全加密功能不提供用户主密钥的生成和备份服务,您需要自行生成用户主密钥。一旦您丢失密钥,将无法再访问已有的数据。因此我们建议您妥善备份用户主密钥。
      • 用户主密钥由长度为16字节的16进制字符串组成,本示例以0x00112233445566778899aabbccddeeff为例。常见的生成方法有:密码生成工具(如openssl, openssl rand -hex 16)、编程语言中的random函数。

服务端配置步骤

全加密云数据库在RDS PostgreSQL服务端以扩展(Extension)形式部署。本步骤介绍如何在服务器端安装扩展以及创建加密表。

说明 本步骤需要连接RDS PostgreSQL实例进行操作,连接方法请参见连接PostgreSQL实例
  1. 安装EncDB扩展。
    CREATE EXTENSION encdb;
  2. 创建加密表。
    创建加密表时,您可以根据自身需要,将敏感字段的数据类型替换为对应的加密数据类型。以下表为例,其原始定义如下:
    CREATE TABLE example (
      id      INTEGER,
      name    VARCHAR,
      price   INTEGER,
      miles   REAL,
      secret  TEXT,
      PRIMARY KEY (id)
    );
    如果选择price, miles, secret为敏感数据,创建的加密表定义如下:
    CREATE TABLE example (
      id     INTEGER,
      name   VARCHAR,
      price  rnd_type,
      miles  det_type,
      secret rnd_type,
      PRIMARY KEY (id)
    );
    说明
    • 全加密数据库功能目前支持det_typernd_type两种加密数据类型。其中det_type为确定性加密(同一个敏感数据两次加密得到的密文相同),rnd_type为不确定性加密 (同一个敏感数据两次加密得到的密文不同)。
    • 当您在应用程序中使用det_typernd_type时,需要将全加密数据库det_type和rnd_type对应的宿主变量转换为string数据类型。
    • 您不能直接修改原有表(即ALTER TABLE),而是需要新建一个加密表,然后再将原表数据通过SDK加密后导入。

客户端配置步骤

本步骤介绍客户端如何连接数据库并进行数据加密解密操作。

说明 本示例以Maven构建Java项目为例。
  1. 安装EncDB依赖包。
    mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=<安装的Jar包名> -Dversion=<安装的Jar版本> -Dpackaging=jar -Dfile=<下载的Jar包所在路径>/<安装的Jar包名.jar>
    示例:
    mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=libencdb -Dversion=1.2.4 -Dpackaging=jar -Dfile=libs/libencdb-1.2.4.jar
    说明 此示例中EncDB依赖包在libs路径下。
  2. 添加依赖。
    您需要在pom.xml中添加如下依赖:
       <dependency>
          <groupId>com.alibaba.encdb</groupId>
          <artifactId>libencdb</artifactId>
          <version>1.2.4</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
       <dependency>
         <groupId>org.bouncycastle</groupId>
         <artifactId>bcprov-jdk15on</artifactId>
         <version>1.62</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->
       <dependency>
         <groupId>org.bouncycastle</groupId>
         <artifactId>bcpkix-jdk15on</artifactId>
         <version>1.62</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
       <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
         <version>1.2.62</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
       <dependency>
         <groupId>org.postgresql</groupId>
         <artifactId>postgresql</artifactId>
         <version>42.2.23</version>
       </dependency>
       <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>24.1.1-jre</version>
       </dependency>
  3. 全加密功能使用示例。
    1. 连接数据库。
      说明 此示例中MEK仅为测试用,实际应用中请使用自己的MEK。参数MekEncAlgo只作为EncDB SDK的加解密模块使用,不会直接传送给服务器端。
       Class.forName("org.postgresql.Driver");
      
       String hostname = "pgm-uf6qw1ap115gr2****.pg.rds.aliyuncs.com";
       String port = "5432";
       String dbname = "encdbtest";
       String username = "username";
       String password = "userpassword";
       String tableName = "example";
       String mek = "0x00112233445566778899aabbccddeeff";
      
       String dbUrl = "jdbc:postgresql://" + hostname + ":" + port + "/" + dbname + "?binaryTransfer=true";
       Connection dbConnection = DriverManager.getConnection(dbUrl, username, password);
      
       /*创建EncdbSDK实例*/
       EncdbSDK sdk = EncdbSDKBuilder.newInstance()
               .setDbConnection(dbConnection)
               .setMek(mek)
               .setEncAlgo(Constants.EncAlgo.SM4_128_CBC)
               .setDekGenMode(Constants.DekGenMode.LOCAL)
               .setSdkMode(Constants.SDKMode.Crypto)
               .build();
      
       Cryptor crypto = sdk.getCryptor();
      上述示例中关键参数解释及取值示例如下:
      参数 取值示例(字符串类型) 说明
      Mek 0x00112233445566778899aabbccddeeff

      用户主密钥。

      取值范围:长度为16字节的16进制字符串。

      EncAlgo SM4_128_CBC

      加密算法。

      取值范围:
      • AES_128_GCM
      • AES_128_CBC
      • SM4_128_CBC(默认值)
      DekGenMode LOCAL

      生成数据密钥的方式。固定为LOCAL,不能修改。

      SdkMode Crypto SDK模式。固定为Crypto,不能修改。
    2. 插入加密数据。
       PreparedStatement stmt = dbConnection.prepareStatement("insert into " + tableName + " (id, name, price, miles, secret) values(?,?,?,?,?)");
       int price = 1234;
       float miles = 12.34f;
       String secret = "aliyun";
      
       stmt.setInt(1, 1);
       stmt.setString(2, "name");
       stmt.setBytes(3, crypto.encrypt(tableName, "price", String.valueOf(price)));
       stmt.setBytes(4, crypto.encrypt(tableName, "miles", String.valueOf(miles)));
       stmt.setBytes(5, crypto.encrypt(tableName, "secret", secret));
       stmt.execute();
    3. 查询解密数据。
       String sqlCmd = "SELECT * from " + tableName + " where miles = ?";
       PreparedStatement stmt = dbConnection.prepareStatement(sqlCmd);
       stmt.setBytes(1, crypto.encrypt(tableName, "miles", "12.34"));
       ResultSet rs = stmt.executeQuery();
       while (rs.next()) {
           int id = rs.getInt(1);
           String name = rs.getString(2);
      
           int price = Integer.parseInt(crypto.decryptString(rs.getBytes(3)));
           float miles = Float.parseFloat(crypto.decryptString(rs.getBytes(4)));
           String text = crypto.decryptString(rs.getBytes(5));
      
           System.out.println(id + ", " + name + ", " + price + ", " + miles + ", " + text);
       }
    查询结果:
    • 已加密的数据在客户端查询时被解密,您可以查询到明文。
      1, name, 1234, 12.34, aliyun
    • 已被加密的数据在服务器端无法查看,能够有效防御来自云平台外部和内部的安全威胁,时刻保护用户数据。
      postgres=# select * from example;
       id | name |                                  price                                   |                                  miles                                   |                                  secret
      ----+------+--------------------------------------------------------------------------+--------------------------------------------------------------------------+--------------------------------------------------------------------------
        1 | name | \xdf4901df087c6a3e0325175bb76942c684191a8dda2a8d0c35f295dc1e30eaeaa0c0e3 | \x315102ea5ab8a659066ab672e6dfbfd89a3a2b360bf6efe3787931e00f61af05f7408c | \xed4903dfd1bda1a89ad6aa7e8905c0e6305e15db4bc9ce2d2cfac9e25094d2a3ed367d
      (1 行记录)