RDS PostgreSQL提供全加密数据库功能,数据在用户侧加密后传入云数据库,能够有效防御来自云平台外部和内部的安全威胁,时刻保护用户数据,让云上数据成为您的私有资产。
背景信息
全加密云数据库是达摩院数据库与存储实验室的自研产品,可以杜绝云数据库服务、应用服务等数据拥有者以外的任何人接触到用户的明文数据,避免云端发生数据泄漏。
全加密云数据库采用阿里云的加密计算能力实现可信执行环境TEE(Trusted Execution Environment),使得数据在用户侧(客户端)加密后传入云数据库(服务端)。在云数据库上数据全程以密文形式存在,避免云平台软件(如OS、VMM、特权系统管理工具等)、管理人员(如DBA)接触到明文数据,同时仍然支持所有的数据库事务、查询、分析等操作,做到了云数据库内数据的可用不可见。
产品架构
适用场景
全加密云数据库在提供强大的安全保护能力的同时,仍然保障数据库系统的高性能、高可靠和低成本,适用于任何对敏感数据有机密性和完整性需求的业务场景。针对不同业务场景所面临的不同数据安全问题,以下列举了一些全加密云数据库适用的典型场景:
- 应用服务面向数据库服务的数据加密
在一般的应用场景中,数据的拥有者即为应用服务方。应用服务方希望防止数据库服务及其运维人员接触到任何应用数据,同时保证数据库的正常运作。
- 终端用户面向应用服务的数据加密
在面向终端用户的应用场景中,部分数据(如健康数据、财务数据等)的拥有者为用户本人。用户希望应用服务只提供数据管理和分析的能力,不能接触私人明文数据。
- 安全可靠的加密数据共享
在需要将部分数据与第三方分享时,数据拥有者希望在不泄漏自身密钥的前提下完成加密数据的分享。
创建全加密云数据库
当前该功能尚处于邀测阶段,阿里云会对部分用户发出邀测链接,收到邀测链接的用户才能打开链接执行如下步骤。
使用全加密云数据库
您可以通过配套的客户端SDK访问全加密数据库。业务中通过SDK使用全加密数据库功能请参照下述步骤。
- 定义加密字段
全加密云数据库同时支持加密和非加密字段。您可以根据自身需要,选择需要被加密的敏感字段,将敏感字段的数据类型替换为对应的加密数据类型。
以user_profile表为例,其原始定义如下:
CREATE TABLE user_profile ( id int, name varchar, dob date, department varchar, salary int, primary key (id) )
如果选择ID、name、salary、dob为敏感数据,您不能直接修改原有表,需要新建一个加密表,然后再将原表数据导入。创建的新表定义如下:
CREATE TABLE user_profile ( id enc_int4, name enc_varchar, dob enc_date, department varchar, salary enc_int4, primary key (id) )
原表和加密表数据类型的对应关系如下表。
原表数据类型 加密表数据类型 int enc_int4 float enc_float4 text enc_text timestamp enc_timestamp int8 enc_int8 float8 enc_float8 - 修改密文查询语句
查询敏感字段时需要将敏感字段的值从原数据类型转换为加密数据类型。
以salary字段为例,原查询语句为:
String selectSQL = "SELECT ID,NAME FROM user_profile WHERE SALARY > ? and SALARY < ?"; preparedStatement.set(1, 2000); preparedStatement.set(2, 5000);
需要修改为:
String selectSQL = "SELECT ID,NAME FROM user_profile WHERE SALARY > ? and SALARY < ?"; preparedStatement.set(1, sdk.encrypt(2000)); preparedStatement.set(2, sdk.encrypt(5000));
- 解析密文执行结果
通过查询获得查询结果后,敏感字段内容将是密文形式,因此需要解密得到明文结果。
以user_profile表中
id
和name
字段为例:Int id = sdk.decrypt(result.get("ID")); String name = sdk.decrypt(result.get("NAME"));
完整客户端代码
// 连接到数据库
Connection con = DriverManager.getConnection("jdbc:XXX", "user1", "user1");
// 初始化Crypto SDK,并将用户根密钥Root Key通过远程证明传递到TEE中
Crypto sdk(con, ROOT_KEY);
String selectSQL = "SELECT ID,NAME FROM user_profile WHERE SALARY > ? and SALARY < ?
and DOB < ?";
PreparedStatement stat = con.prepareStatement(sql);
// 获取对应的Encryptor对不同字段进行加密
Encryptor enc_id = sdk.GetEncryptorByName("USER_PROFILE", "ID");
Encryptor enc_dob = sdk.GetEncryptorByName("USER_PROFILE", "DOB");
preparedStatement.set(1, enc_id.encypt(2000));
preparedStatement.set(2, enc_id.encypt(5000));
preparedStatement.set(3, enc_dob.encypt("1990-01-01"));
ResultSet rs = preparedStatement.executeQuery(selectSQL);
// 获取Decryptor对查询结果解密
Decryptor dec = sdk.GetDecryptor();
for (Result& r : rs) {
// dec将自动获取ID,NAME字段对应的数据密钥
Int id = dec.decrypt(r.get("ID"));
String name = dec.decrypt(r.get("NAME"));
}
- 初始化SDK时需要您提供正确的根密钥(Root Key)。
- 不同的数据字段可以用不同的数据密钥加密(Encryptor)。
- 执行结果在返回客户端后统一解密(Decryptor)。
在项目程序中使用SDK
您可以参照如下步骤使用SDK,更多详情请参见SDK中README.md文件。
点此下载配套客户端SDK。
- 当前仅提供x86_64版本的SDK,并在Linux上测试通过。
- 客户端SDK中提供了完整的C++示例代码,请参见文件example.cpp自行编译测试。
- 客户端SDK中提供了完整的API接口说明,请参见文件API.md。
- 解压到目标路径下。例如path/to/encdbsdk/。
- 在程序代码中调用SDK中提供的API,通常只需要crypto.h文件。示例如下:
#include "crypto.h"
- 编译程序时,将全加密数据库的SDK添加到编译参数中,通常可以在程序Makefile中添加。示例如下:
CFLAGS += -I<path/to/encdbsdk>/include LDFLAGS += -L<path/to/encdbsdk>/lib64 -lencdb
- 运行程序。
说明 由于SDK以动态库方式进行链接,请确保<path/to/encdbsdk>/lib64在系统查找路径内。可以在Shell下通过如下命令进行配置:
export LD_LIBRARY_PATH=<path/to/encdbsdk>/lib64:$LD_LIBRARY_PATH
效果示例
- 对于服务器端或者未授权用户,仅能访问到敏感数据的密文,如下图所示。
- 对于授权用户,即拥有正确根密钥的用户,可以在取回密文数据后,使用数据密钥解密得到敏感数据明文,如下图所示。
说明
Plain value列为右侧密文解密得到的明文数据。