本文介绍如何通过客户端使用全密态数据库功能。
前提条件
已开通全密态数据库。更多信息,请参见开通全密态数据库。
已定义敏感数据。具体操作,请参见定义敏感数据。
获取加密数据库连接信息。您首先需要获取加密数据库的连接信息,如域名(host)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等。实例内外网地址获取方式请参见查看或修改连接地址和端口。
本文中介绍的应用程序使用的开发语言为Java,请确保已具备Java开发环境,建议使用Java版本为
1.8
及以上,Maven版本为3.9.2
,使用的开发工具为IntelliJ IDEA Community Edition 2022.3.2
。
注意事项
请保存好您设置的主密钥MEK
。
客户端使用示例
全密态数据库对查询结果中的目标敏感数据进行加密。为了让应用能够使用全密态功能,全密态支持以下客户端接入:
接入方式 | 说明 | 是否需要改动业务代码 | |
应用程序 | EncJDBC | 自动识别加密数据类型并对数据进行加密解密。 | (推荐使用)基本不需要改动业务代码。 |
EncDB SDK | 在客户端调用EncDB SDK提供的加解密函数,对明文数据进行加密或者对密文数据进行解密。 | 需要。 | |
psql命令行工具 | 直接连接数据库查询,只显示密文数据。 | 仅用于查询,不进行业务开发,无需改动业务代码。 | |
DMS控制台等可视化交互工具 |
EncJDBC
下载驱动程序及依赖配置
下载EncJDBC驱动。
EncJDBC
依赖于社区提供的PostgreSQL驱动工作。RDS PostgreSQL小版本
服务端encdb插件版本号
客户端EncDB依赖包
20230830或以上版本
1.1.13或以上版本
Maven依赖配置。
说明本示例以Maven构建Java项目为例。
通过如下命令将
EncJDBC
依赖包安装至您的本地仓库:mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=<安装的Jar包名> -Dversion=<安装的Jar版本> -Dpackaging=jar -Dfile=<安装的Jar包文件名>
示例:
mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=encjdbc -Dversion=1.0.6 -Dpackaging=jar -Dfile=D:\encdb\libs\encjdbc-1.0.6.jar
说明此示例中EncDB依赖包在
D:\encdb\libs
路径下。此示例使用的Maven版本为
3.9.2
,如果您安装报错,请升级Maven版本后再试。
在本地仓库安装
EncJDBC
依赖包的基础上,您需要在自己的Maven项目pom.xml配置文件中加入以下依赖项。<dependencies> ... <dependency> <groupId>com.alibaba.encdb</groupId> <artifactId>encjdbc</artifactId> <version>1.0.6</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> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.2</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> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.jgrapht</groupId> <artifactId>jgrapht-core</artifactId> <!-- jgrapht does not support java 1.8 since 1.5.0 --> <version>1.4.0</version> </dependency> ... </dependencies>
通过全密态客户端查询(代码示例)
本示例所展示的代码仅用于演示配置方式,请勿在实际业务代码中将password
、mek
以明文方式设置在代码中,建议使用外部配置文件或环境变量等其他方式进行处理后,再在代码中引用。
URL配置说明
您可以像使用任意一个JDBC一样使用
EncJDBC
。但是您需要预先在EncJDBC
中配置和您数据安全相关的如下信息。// 准备好域名(hostname)、端口(port)、数据库名称(dbname)、用户名(username)、密码(password)等连接信息 // 详见数据安全相关参数 String mek=...; String encAlgo=...; String dbUrl = String.format("encjdbc:postgresql://%s:%s/%s?mek=%s&enc_algo=%s", hostname, port, dbname, mek, encAlgo); Class.forName("com.alibaba.encdb.encjdbc.EncDriver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // ... 发起查询 ...
说明URL配置方式中,多个参数可以用
&
进行拼接。mek
及其他参数均在客户端本地进行处理、并以安全方式进行分发(信封加密)到服务端,始终保证mek
不泄露。
完整代码示例
// 以下域名(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"; String dbUrl = String.format("encjdbc:postgresql://%s:%d/%s?mek=%s&enc_algo=%s", hostname, port, dbname, mek, encAlgo); Class.forName("com.alibaba.encdb.encjdbc.EncDriver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // create table dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example"); dbConnection.createStatement().executeUpdate("CREATE TABLE example (id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"); // insert data PreparedStatement stmt = dbConnection.prepareStatement("INSERT INTO example (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.setInt(3, price); stmt.setFloat(4, miles); stmt.setString(5, secret); stmt.execute(); // check plaintext data String sqlCmd = "SELECT * FROM example WHERE price > ?"; PreparedStatement stmt = dbConnection.prepareStatement(sqlCmd); stmt.setInt(1, 100); ResultSet rs = stmt.executeQuery(); while (rs.next()){ int id = rs.getInt(1); String name = rs.getString(2); int price = rs.getInt(3); float miles = rs.getFloat(4); String secret = rs.getString(5); System.out.println(id + ", " + name + ", " + price + ", " + miles + ", " + secret); }
输出结果示例:
1, name, 1234, 12.34, aliyun
通过上述EncJDBC
代码示例,可以看到,以上过程仅修改了驱动加载以及URL配置部分,其他过程与普通数据库访问完全一致。您不需要修改任何业务相关代码。
EncDB SDK
下载驱动程序及依赖配置
下载EncDB SDK驱动。
EncDB SDK
依赖于社区提供的PostgreSQL驱动工作。RDS PostgreSQL小版本
服务端encdb插件版本号
客户端EncDB依赖包
20230830或以上版本
1.1.13或以上版本
Maven依赖配置。
说明本示例以Maven构建Java项目为例。
通过如下命令将
EncDB SDK
依赖包安装至您的本地仓库:mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=<安装的Jar包名> -Dversion=<安装的Jar版本> -Dpackaging=jar -Dfile=<安装的Jar包文件名>
示例:
mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=libencdb -Dversion=1.2.12 -Dpackaging=jar -Dfile=D:\encdb\libs\libencdb-1.2.12.jar
说明此示例中EncDB依赖包在
D:\encdb\libs
路径下。此示例使用的Maven版本为
3.9.2
,如果您安装报错,请升级Maven版本后再试。
在本地仓库安装
EncDB SDK
依赖包的基础上,您需要在自己的Maven项目pom.xml配置文件中加入以下依赖项。<dependencies> ... <dependency> <groupId>com.alibaba.encdb</groupId> <artifactId>libencdb</artifactId> <version>1.2.12</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</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>31.1-jre</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.4</version> </dependency> ... </dependencies>
通过全密态客户端查询(代码示例)
本示例所展示的代码仅用于演示配置方式,请勿在实际业务代码中将password
、mek
以明文方式设置在代码中,建议使用外部配置文件或环境变量等其他方式进行处理后,再在代码中引用。
SDK配置说明
您需要在处理收发密文数据前,使用
EncDB SDK
对数据进行加解密。EncDB SDK
提供了对应的接口,用于您初始化SDK对象时配置和您数据安全相关的参数。通常您只需要配置主密钥(setMek)以及期望的加密算法(setEncAlgo),其他参数建议您使用默认缺省配置。// 准备好域名(hostname)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等连接信息 // 建立数据库连接,任意JDBC版本均可 String dbUrl = String.format("jdbc:postgresql://%s:%s/%s?binaryTransfer=true", hostname, port, dbname); Class.forName("org.postgresql.Driver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // 初始化SDK String mek=...; Constants.EncAlgo encAlgo=...; EncdbSDK sdk = EncdbSDKBuilder.newInstance() .setDbConnection(dbConnection) .setMek(mek) .setEncAlgo(encAlgo) .build(); Cryptor cryptor = sdk.getCryptor(); // 调用加解密接口 // byte[] cipherBytes = cryptor.encrypt(...); // XXX value = cryptor.decryptXXX(...): // ... 发起查询 ...
说明mek
及其他参数均在客户端本地进行处理、并以安全方式进行分发(信封加密)到服务端,始终保证mek
不泄露。完整代码示例
// 以下域名(hostname)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等连接信息需要更新为您的实例信息 String hostname = "hostname"; String port = "port"; String dbname = "db"; String username = "user"; String password = "password"; // 建立数据库连接 String dbUrl = String.format("jdbc:postgresql://%s:%s/%s?binaryTransfer=true", hostname, port, dbname); Class.forName("org.postgresql.Driver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // 初始化SDK String mek="00112233445566778899aabbccddeeff"; // 只是示例,建议用更复杂的密钥 Constants.EncAlgo encAlgo=Constants.EncAlgo.SM4_128_CBC; EncdbSDK sdk = EncdbSDKBuilder.newInstance() .setDbConnection(dbConnection) .setMek(mek) .setEncAlgo(encAlgo) .build(); Cryptor cryptor = sdk.getCryptor(); // create table dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example"); dbConnection.createStatement().executeUpdate("CREATE TABLE example (id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"); // insert data PreparedStatement stmt = dbConnection.prepareStatement("INSERT INTO example (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, cryptor.encrypt("example", "price", price)); stmt.setBytes(4, cryptor.encrypt("example", "miles", miles)); stmt.setBytes(5, cryptor.encrypt("example", "secret", secret)); stmt.execute(); // check plaintext data String sqlCmd = "SELECT * FROM example WHERE price > ?"; stmt = dbConnection.prepareStatement(sqlCmd); stmt.setBytes(1, cryptor.encrypt("example", "price", 100)); ResultSet rs = stmt.executeQuery(); while (rs.next()) { int id = rs.getInt(1); String name = rs.getString(2); price = cryptor.decryptInt(rs.getBytes(3)); miles = cryptor.decryptFloat(rs.getBytes(4)); String text = cryptor.decryptString(rs.getBytes(5)); System.out.println(id +", " + name + ", " + price + ", " + miles + ", " + text); }
输出结果示例:
1, name, 1234, 12.34, aliyun
相关参考
Java SDK模块介绍
EncDB SDK
主要包含以下几个Java功能模块:
psql命令行
全密态数据库支持命令行直接查询,例如psql命令行执行SELECT * FROM example;
。
可以看到,id
、name
列是明文,price
、miles
、secret
列是密文。已被加密的数据在服务器端无法查看,能够有效防御来自云平台外部和内部的安全威胁,时刻保护用户数据。
DMS控制台
全密态数据库支持通过DMS等可视化交互工具直接查询,例如DMS。
可以看到,id
、name
列是明文,price
、miles
、secret
列是密文。
常见问题
Q:连接数据库提示报错
org.postgresql.util.PSQLException: ERROR: db_process_msg_api: process message failure - returned 0xf7070000
。A:错误码0xf7070000表示MEK密钥导入失败。可能原因为同一个账号在连接同一个加密数据库时,使用了不同的MEK,更换主密钥会导致原密钥加密的数据无法访问,请使用原密钥连接数据库。
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模块,以解决访问权限问题。