全部产品
Search
文档中心

云数据库 RDS:EncJDBC

更新时间:Jul 19, 2024

如果您希望使用全密态功能对数据库表中的被保护数据列进行加密,并且使用Java应用程序访问数据库,可以使用全密态客户端驱动程序EncJDBC接入全密态数据库,接入操作便捷,能够降低使用全密态功能的成本。本文介绍如何通过EncJDBC访问全密态数据库。

在持有用户密钥的情况下,EncJDBC能够自动完成密文数据的解密并返回明文数据,过程对应用透明,应用程序只需配置几行代码就可以接入全密态数据库,降低了使用全密态功能的成本。

前提条件

  • 已开通全密态功能,详情请参见开通全密态功能

  • 已获取加密数据库连接信息。您首先需要获取加密数据库的连接信息,如域名(host)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等。

  • 已配置数据保护规则。具体操作请参见配置数据保护规则

注意事项

  • 请保存好您设置的主密钥MEK

  • Java使用JDK 1.8或以上版本。

    说明

    本文中使用的Maven版本为3.9.2,使用的开发工具为IntelliJ IDEA Community Edition 2022.3.2

操作步骤

步骤一:Maven依赖配置

您需要在自己的Maven项目配置文件pom.xml中加入以下依赖项。

<dependencies>
  <dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-encdb-mysql-jdbc</artifactId>
    <version>1.0.9-1</version>
  </dependency>
</dependencies>

步骤二:通过全密态客户端查询(代码示例)

您可以像使用任意一个JDBC一样使用我们的EncJDBC。但是您需要预先在EncJDBC中配置和您数据安全息息相关的参数,包括MEK(主密钥)、ENC_ALGO(加密算法)。

具体参数解释及取值示例如下:

参数

取值示例(字符串类型)

说明

MEK

00112233445566778899aabbccddeeff

用户主密钥,由用户自定义指定。

常见的生成方法有:密码生成工具(如openssl, openssl rand -hex 16)、编程语言中的random函数、或者从第三方密钥管理服务(KMS)获取。

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

警告

用户主密钥是您访问加密数据的根凭据,出于安全考虑,全密态数据库不持有并管理您的主密钥,也不提供用户主密钥的生成和备份服务,您需要自行生成用户主密钥。一旦您丢失密钥,将无法再访问已有的数据。因此我们建议您妥善备份用户主密钥。

ENC_ALGO

SM4_128_CBC

指明被保护数据将要使用的加密算法。

取值范围:

  • 国际算法:

    • AES_128_GCM

    • AES_128_CTR

    • AES_128_CBC

    • AES_128_ECB(不推荐)

  • 国密算法:

    • SM4_128_GCM(默认)

    • SM4_128_CTR

    • SM4_128_CBC

    • SM4_128_ECB(不推荐)

说明
  • AES_128_ECB和SM4_128_ECB加密算法安全性较弱,请谨慎使用,推荐适用其他安全性更高的加密算法。

  • 可选,默认为SM4_128_GCM。

配置MEK和ENC_ALGO

下面介绍三种配置MEKENC_ALGO的方法。如果您的JDBC配置了两种以上的方法,优先级顺序为:JDBC properties配置 > 文件配置 > URL配置。

说明
  • URL配置方式中,多个参数可以用&进行拼接。

  • 以下三种连接方式,MEK均在客户端本地进行处理、并以安全方式分发(信封加密)到服务端,始终保证MEK不泄露。

JDBC properties配置

标准的JDBC在连接时,可以通过Properties设置用户自定义属性。以下是一个通过这种方式配置JDBC属性并运行JDBC的例子:

// 准备好域名(hostname)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等连接信息
// ...

String mek=...;
String encAlgo=...;

Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
props.setProperty("ENC_ALGO", encAlgo);

String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, props);

// ... 发起查询 ...
文件配置

支持通过配置文件来导入参数方式,配置需要的MEK等参数。您可以在项目中设置一个名为encJdbcConfigFile的property,将值设置为配置文件路径即可(缺省时,默认使用encjdbc.conf的文件)。

配置文件的内容如下:

MEK=
ENC_ALGO=

您可以通过以下两种方式放置配置文件的位置:

  • 将文件放入项目中的resources目录下,如下图所示:image.png

  • 将文件放入项目根目录,即程序的运行时目录。

通过文件配置方式,在做完文件配置后,您可以不用在程序中做额外的配置,如下面所示:

// 准备好域名(hostname)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等连接信息
// ...

String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// ... 发起查询 ...
URL配置

支持通过URL链接中嵌入MEKENC_ALGO等参数。如下面所示:

// 准备好域名(hostname)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等连接信息
// ...

String mek=...;
String encAlgo=...;

String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?MEK=%s&ENC_ALGO=%s", hostname, port, dbname, mek, encAlgo);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// ... 发起查询 ...

完整代码示例(以JDBC properties配置为例)

// 以下域名(hostname)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等连接信息需要更新为您的实例信息
String hostname = "hostname";
String port = "port";
String dbname = "db";
String username = "user";
String password = "password";

String mek="00112233445566778899aabbccddeeff";  // 只是示例,建议用更复杂的密钥
String encAlgo="SM4_128_CBC";

Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
props.setProperty("ENC_ALGO", encAlgo);

String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, props);

int[] intData = {1, 2, 3, 4, 5, 6};
String[] strData = {"abc", "bcd", "1", "def", "efg", "fgi"};

// create table
connection.createStatement().executeUpdate("drop table if exists test");
connection.createStatement().executeUpdate("create table test (a int, b text)");

// insert data
for (int i = 0; i < 6; i++) {
    PreparedStatement pstmt = connection.prepareStatement("insert into test values (?,?)");
    pstmt.setInt(1, intData[i]);
    pstmt.setString(2, strData[i]);
    pstmt.executeUpdate();
}

// check plaintext data
ResultSet rs = connection.createStatement().executeQuery("select * from test");
while (rs.next()) {
    for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
        System.out.print(rs.getString(i + 1));
        System.out.print("\t");
    }
    System.out.print("\n");
}

输出结果:

1	abc	
2	bcd	
3	cde	
4	def	
5	efg	
6	fgi	

常见问题

  • Q:运行程序时报错Exception in thread "main" java.lang.IllegalAccessError: class com.alibaba.encdb.common.SymCrypto (in unnamed module @0x5c0369c4) cannot access class com.sun.crypto.provider.SunJCE (in module java.base) because module java.base does not export com.sun.crypto.provider to unnamed module @0x5c0369c4,如何处理?

    A: 该报错可能是因为您的JDK版本较高导致的模块间权限问题,请在运行时添加VM option参数--add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED将com.sun.crypto.provider导出给Unnamed模块,以解决访问权限问题。

  • Q:运行程序时报错failed in mek provision: you might have an incorrect mek setting. Detail:gcmEncrypt error,如何处理?

    A:该问题常见于Oracle系列的JDK,如需解决此问题,您可以任选如下两种方式之一:

    • 使用Amazon Correto系列的JDK。

    • 仍然使用Oracle系列的JDK,但需要手动配置Security provider。具体步骤如下:

      1. 找到JDK的安装路径。

      2. 安装路径/conf/security/路径下,找到java.security文件。

      3. 编辑java.security文件,在List of providers and their preference orders (see above):区域,补充如下内容:

        security.provider.14=org.bouncycastle.jce.provider.BouncyCastleProvider