使用全密态数据库实例时,不同用户之间天然存在密文数据隔离。本文介绍如何通过授权管理实现不同用户之间的数据融合计算,以及允许数据库管理员(DBA)进行高危数据操作。
功能介绍
全密态数据库中,用户数据使用各自的数据密钥进行加密,不同用户之间的密文数据天然存在隔离。若需要使用多方用户的数据进行联合查询,则需要由数据所有者对查询方进行授权,以允许其访问该数据所有者的密文数据。该过程称为多用户授权管理。
在全密态数据库中,通过行为控制列表(BCL,Behavior Control List)实现多用户授权访问功能。通过BCL授权管理,查询方(Subject)能够在未了解授权方(Issuer,即数据所有者)数据内容的情况下完成数据联合查询。授权方无需担心己方数据的泄露,同时可以通过灵活地签发BCL授权(同意授权/撤销授权)来限制查询方的行为,从而及时有效地避免数据被非预期使用。
特别地,当用户需要数据库管理员(DBA)在全密态数据库中执行高风险操作(如创建用户密钥或进行明密文转换)时,可以通过签发BCL授权,授权数据库管理员(DBA)在用户账号下进行相关操作。在这种情况下,查询方和授权方为同一数据库用户。
前提条件
已开通全密态数据库。具体操作,请参见开通全密态数据库。
说明RDS PostgreSQL实例的内核小版本大于等于20230830,如需升级内核小版本,请参见升级内核小版本。
已分别为授权方和查询方创建账号。具体操作,请参见创建账号。
已定义敏感数据。具体操作,请参见定义敏感数据。
已使用EncDB SDK的方式,在授权方和查询方各自完成了一次数据库连接,并分别为二者构建了相应的测试数据。具体操作,请参见EncDB SDK客户端使用说明。
步骤一:初始化公钥和私钥
分别获取授权方和查询方的公钥与私钥。
安装OpenSSL工具。
本文以OpenSSL开源密码工具获取公私钥为例。如果您使用Linux系统,系统会自带OpenSSL工具,无需安装。如果您使用Windows系统,请获取OpenSSL软件包并安装。
说明如果RDS PostgreSQL实例规格为全密态基础版(非Intel SGX安全增强型规格的RDS PostgreSQL实例),需要生成基于SM2算法的公钥和私钥,请执行
openssl ecparam -list_curves
命令,确认当前OpenSSL版本是否支持SM2加密算法。如果返回结果中包含SM2,则表示支持。否则需要升级OpenSSL到支持SM2的版本(1.1.1及以上版本)。根据全密态数据库规格,获取授权方和查询方的公钥与私钥。
生成的公钥和私钥文件分别为
pub_key.pem
和pri_key_pkcs8.pem
。全密态硬件加固版(Intel SGX)
全密态硬件加固版(Intel SGX),是指Intel SGX 安全增强型规格的RDS PostgreSQL实例。详细的规格清单请参见RDS PostgreSQL主实例规格列表。
获取公钥与私钥的方法:
使用OpenSSL生成RSA私钥
openssl genpkey -algorithm RSA -out pri_key_pkcs8.pem -pkeyopt rsa_keygen_bits:3072
说明3072:密钥长度。可根据实际情况调整为其他符合安全标准的密钥长度。
使用OpenSSL生成RSA公钥
openssl rsa -in pri_key_pkcs8.pem -pubout -out pub_key.pem
全密态基础版
全密态基础版,是指非Intel SGX安全增强型规格的RDS PostgreSQL实例。详细的规格清单请参见RDS PostgreSQL主实例规格列表。
获取公钥与私钥的方法:
使用OpenSSL生成SM2私钥
# 生成PKCS#1私钥 openssl ecparam -out ec_param.pem -name SM2 -param_enc explicit -genkey # 转换成PKCS#8私钥 openssl pkcs8 -topk8 -inform PEM -in ec_param.pem -outform pem -nocrypt -out pri_key_pkcs8.pem
使用OpenSSL生成SM2公钥
openssl ec -in ec_param.pem -pubout -out pub_key.pem
分别初始化授权方和查询方的公钥和私钥。
分别在授权方和查询方各自的业务代码中,初始化授权方和查询方的公钥及私钥。
说明使用OpenSSL生成的PEM文件在内容上会自动添加换行符(newline)。在某些编辑器中,可能会对其显示进行优化,从而导致在手动拷贝时出现漏掉换行符的情况。建议通过程序代码读取文件内容,以确保其准确性。
//参与方用户私钥 String userPrkPemString = readPemFile("path/to/pri_key_pkcs8.pem"); //参与方用户公钥 String userPukPemString = readPemFile("path/to/pub_key.pem"); //初始化,只需要初始化执行一次,无需重复执行 KeyManager km = sdk.getKeyManager(); km.registerCertificate(userPrkPemString, userPukPemString);
步骤二:授权多用户访问
定义授权内容。
String bclBodyJsonString = """{ "version": 1, "serial_num": "a121bac0-5cb3-4463-a2b2-1155ff29f4c8", "issuer_pukid": "p81x+WqYb7BR0yP0LK0qiEaxgLDqwuIjfJhgC0mMJcE=", "subject_pukid": "qIPPfgTJEEG/9WkjP0E5LLAijZ14h/Qgb2EfmBZCWSo=", "validity": { "not_after": "20250820111111+0800", "not_before": "20240820111111+0800" }, "policies": { "issuer_dek_group": [ { "min": 1, "max": 100000, "groupid": "5bc60759-5b05-45ec-afc1-ffca1229e554" } ], "result_dek": "SUBJECT", "subject_dek_group": [ { "min": 1, "max": 100000, "groupid": "53413af9-f90a-48a9-93b6-49847861b823" } ], "operation": [ "*" ], "postproc": "NULL", "preproc": "NULL" } } """;
参数说明
参数
取值样例
说明
version
1
版本号,当前固定为1。
serial_num
"a121bac0-5cb3-4463-a2b2-1155ff29f4c8"
序列号,UUID格式,自定义,全局唯一。
说明可使用UUID生成工具生成序列号。
issuer_pukid
"p81x+WqYb7BR0yP0LK0qiEaxgLDqwuIjfJhgC0mMJcE="
授权方公钥摘要。基于生成的公钥文件(pub_key.pem),获取方法:
全密态硬件加固版(Intel SGX)
openssl sha256 -binary pub_key.pem | openssl base64
全密态基础版
openssl sm3 -binary pub_key.pem | openssl base64
subject_pukid
"qIPPfgTJEEG/9WkjP0E5LLAijZ14h/Qgb2EfmBZCWSo="
查询方用户公钥摘要,配置方法与issuer_pukid相同。
validity
{ "not_before": "20240820111111+0800", "not_after": "20250820111111+0800"}
授权有效期。需使用GeneralizedTime时间格式。
"not_before":有效期开始时间。
"not_after":有效期结束时间。
policies
issuer_dek_group
[ { "min": 1, "max": 100000, "groupid": "5bc60759-5b05-45ec-afc1-ffca1229e554" }]
授权方允许使用的数据密钥(DEK)分组。
"groupid":DEK分组ID。
"min":分组内授权的最小DEK ID。
"max":分组内授权的最大DEK ID。
说明给定groupid下,DEK ID取值严格单调递增。
groupid获取方法:
SELECT encdb_get_cc_entry_by_name(encdb.keyname_generate('<user_name>', '<database_name>', '<schema_name>', '<table_name>', '<column_name>'));
说明<user_name>
为授权方的用户名。<table_name>
为授权访问的授权方目标表名称。<column_name>
为授权访问的授权方目标列名称。
subject_dek_group
[ { "min": 1, "max": 100000, "groupid": "53413af9-f90a-48a9-93b6-49847861b823" }]
查询方允许使用的数据密钥(DEK)分组。
"groupid":DEK分组ID。
"min":分组内授权的最小DEK ID。
"max":分组内授权的最大DEK ID。
说明给定groupid下,DEK ID取值严格单调递增。
获取groupid方法:
SELECT encdb_get_cc_entry_by_name(encdb.keyname_generate('<user_name>', '<database_name>', '<schema_name>', '<table_name>', '<column_name>'));
说明<user_name>
为查询方的用户名。<table_name>
为授权访问的查询方目标表名称。<column_name>
为授权访问的查询方目标列名称。
result_dek
"SUBJECT"
计算结果使用的DEK加密方式。
"SUBJECT":使用当前计算中查询方的DEK加密。
"ISSUER":使用当前计算中授权方的DEK加密。
DEK ID:使用指定DEK ID的DEK加密。
重要如果使用
DEK ID
,直接在此参数配置DEK ID的内容,无需添加双引号。
operation
[ "*"]
允许的计算操作。
"encrypt":加密。
"decrypt":解密。
"cmp":比较。
"*":授权所有操作。
postproc
"NULL"
计算前需要的前置预处理操作。当前固定为NULL,表示无前置预处理操作。
preproc
"NULL"
计算后需要的后置预处理操作。当前固定为NULL,表示无后置预处理操作。
授权多用户访问。
授权方使用己方公钥和私钥,签发BCL,授权查询方访问目标列的数据。
boolean isIssuer = true; bclBodyJsonString = km.issueBCL(bclBodyJsonString, userPukPemString, userPrkPemString, isIssuer);
查询方使用己方公钥和私钥,签发BCL,访问已授权的数据。
boolean isIssuer = false; bclBodyJsonString = km.issueBCL(bclBodyJsonString, userPukPemString, userPrkPemString, isIssuer);
步骤三:(可选)撤销授权
如果授权方需要撤销授权,则使用如下配置。
定义撤销授权内容。
String brlBodyJsonString = """{ "version": 1, "pukid": "dYJ3Wfj/n0eZbuqgQjv8bnBdPXGyWGOlxE/uMy16NXo=", "this_update": "20220819111128+0800", "next_update": "20220919111128+0800", "revoked": [ { "revocation_date": "20220819111128+0800", "serial_num": "a121bac0-5cb3-4463-a2b2-1155ff29f4c8" } ] } """;
参数说明
参数
取值样例
说明
version
1
版本号,当前固定为1。
pukid
"dYJ3Wfj/n0eZbuqgQjv8bnBdPXGyWGOlxE/uMy16NXo="
授权方公钥摘要。需配置为请求授权时BCL中的授权方公钥摘要。配置方法与定义授权内容中相同。
this_update
"20220819111128+0800"
本次撤销列表更新时间,需使用GeneralizedTime时间格式。
next_update
"20220919111128+0800"
下次撤销列表更新时间,需使用GeneralizedTime时间格式。
revoked
revocation_date
"20220819111128+0800"
撤销时间,需使用GeneralizedTime时间格式。
serial_num
"a121bac0-5cb3-4463-a2b2-1155ff29f4c8"
序列号,UUID格式,需配置为请求授权时BCL中的序列号。
授权方签发BCL撤销授权。
brlBodyJsonString = km.revokeBCL(brlBodyJsonString, userPukPemString, userPrkPemString);
应用场景示例
示例一:授权高危操作-明文和密文转换
在存量明文数据库需要启用全密态数据库功能,而又不希望进行数据迁移的情况下,可以通过在原数据库上执行明密文类型的转换,来高效地切换至密文模式(详情请参见明文和密文的转换)。出于安全性考虑,全密态数据库默认不允许数据库用户(包括数据库管理员)直接在全密态数据库上对明密文进行原地转换,这类操作被视为数据安全高危操作。
在明确数据安全风险的前提下,用户可通过签发自授权的BCL,授权用户账号进行明密文类型的原地转换。在此过程中,查询方和授权方均为同一用户账号,即:
定义授权内容时,BCL授权中的
issuer_pukid
与subject_pukid
相同、issuer_dek_group
与subject_dek_group
相同。初始化公钥和私钥时,授权方和查询方使用同一对公钥和私钥,即授权方的
userPukPemString
和userPrkPemString
与查询方的对应密钥相同。
完成自授权BCL签发后,即可在被授权账号下执行相应操作。完整示例代码如下。
示例二:多方数据联合查询
以数据平台公司的业务场景为例,该平台通过合法渠道,在获得用户授权后,收集用户信息,并生成用户画像表。经授权后,平台能够将数据提供给第三方(例如保险公司),以便进行多方数据融合计算,从而实现联合营销。详情请参见多方数据融合计算。
以下为多方数据联合查询的完整示例代码。