摘要:防止数据泄露可以有两种技术路径。一是权限管理,采用最小化授权原则对使用数据的用户和应用程序授权。另一种是数据加密,包括使用 SQL 函数加密和透明加密。
本文分享自华为云社区《【安全无小事】你应该知道的数仓安全——加密函数》,原文作者:zhangkunhn。
前言
最近遇到一个客户场景,涉及共享 schema 的权限问题。场景简单可以描述为:一些用户是数据的生产方,需要在 schema 中创建表并写入数据;另一些用户是数据的消费方,读取 schema 中的数据做分析。对于该 schema 权限管理的一种实现方法是数据生产方在每次创建新表后告知管理员用户使用 grant select on all tables in schema 语法来授予消费方权限。这种方法有一定的局限性。如果生产方在 schema 下面又创建了一些新表,为了授权消费方使用这些新表还需要告知管理员用户再次使用 grant select on all tables in schema 来授权。有没有简单的应对方案?答案是肯定的,可以使用 Alter default privilege。Alter default privilege 用于将来创建的对象的权限的授予或回收。
语法介绍
ALTER DEFAULT PRIVILEGES
[ FOR { ROLE | USER } target_role [, ...] ]
[ IN SCHEMA schema_name [, ...] ]
abbreviated_grant_or_revoke;
复制代码
其中 abbreviated_grant_or_revoke 子句用于指定对哪些对象进行授权或回收权限。对表授权语法是:
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES }
[, ...] | ALL [ PRIVILEGES ] }
ON TABLES
TO { [ GROUP ] role_name | PUBLIC } [, ...]
复制代码
参数说明
已有角色的名称。如果省略 FOR ROLE/USER,则缺省值为当前角色/用户。
取值范围:已有角色的名称。
现有模式的名称。
target_role 必须有 schema_name 的 CREATE 权限。
取值范围:现有模式的名称。
被授予或者取消权限角色的名称。
取值范围:已存在的角色名称。
详见ALTER DEFAULT PRIVILEGES语法说明
场景示例
testdb=# create user creator1 password 'Gauss_234';
CREATE USER
testdb=# create user creator2 password 'Gauss_234';
CREATE ROLE
testdb=# create user user1 password 'Gauss_234';
CREATE USER
--创建共享schema,授予creator1和creator2创建权限,授予user1使用权限
testdb=# create schema shared_schema;
CREATE SCHEMA
testdb=> grant create, usage on schema shared_schema to creator1;
GRANT
testdb=> grant create, usage on schema shared_schema to creator2;
GRANT
testdb=# grant usage on schema shared_schema to user1;
GRANT
--将creator1和creator2在shared_schema中创建表的select权限授予user1
testdb=# alter default privileges for user creator1, creator2 in schema shared_schema grant select on tables to user1;
ALTER DEFAULT PRIVILEGES
--切到creator1,建表
testdb=# \c testdb creator1
You are now connected to database "testdb" as user "creator1".
testdb=> create table shared_schema.t1 (c1 int);
CREATE TABLE
--切到creator2,建表
testdb=> \c testdb creator2
You are now connected to database "testdb" as user "creator2".
testdb=> create table shared_schema.t2 (c1 int);
CREATE TABLE
--切到user1,查询OK
testdb=> \c testdb user1
You are now connected to database "testdb" as user "user1".
testdb=> select * from shared_schema.t1 union select * from shared_schema.t2;
c1
----
(0 rows)
复制代码
查看默认权限的授予现状
查询系统表 pg_default_acl 可以查看当前哪些 schema 被授予了默认权限。从 defaclacl 字段可以看到 creator1 和 creator2 分别授予了 user1 对 shared_schema 中对象的 select 权限(r 表示 read)。
testdb=# select r.rolname, n.nspname, a.defaclobjtype, a.defaclacl from
testdb-# pg_default_acl a, pg_roles r, pg_namespace n
testdb-# where a.defaclrole=r.oid and a.defaclnamespace=n.oid;
rolname | nspname | defaclobjtype | defaclacl
----------+---------------+---------------+--------------------
creator1 | shared_schema | r | {user1=r/creator1}
creator2 | shared_schema | r | {user1=r/creator2}
(2 rows)
复制代码
一些细节
所有在共享 schema 中创建对象的用户都应该出现在 alter default privileges for user 之后的列表中。否则,如果有用户 creator3 没有在列表中,其在共享 schema 中创建的对象或者说那些 Owner 是 creator3 的对象将不能被 user1 查询。因为共享 schema 中 creator3 用户创建的表没有授予 user1 默认权限。
testdb=# create user creator3 password 'Gauss_234';
CREATE USER
testdb=# grant create, usage on schema shared_schema to creator3;
GRANT
testdb=# \c testdb creator3
You are now connected to database "testdb" as user "creator3".
testdb=> create table shared_schema.t3 (c1 int);
CREATE TABLE
testdb=> \c testdb user1
You are now connected to database "testdb" as user "user1".
testdb=> select * from shared_schema.t3;
ERROR: permission denied for relation t3
复制代码
管理员可以通过 alter default privileges for user 将 creator3 放入列表中为 user1 授予访问 creator3 用户创建表的默认权限,也可以由 creator3 用户自己通过 alter default privileges 授权给 user1. 前面语法参数说明中有如果省略 FOR ROLE/USER,则缺省值为当前用户。
testdb=> \c testdb creator3
You are now connected to database "testdb" as user "creator3".
testdb=> alter default privileges in schema shared_schema grant select on tables to user1;
ALTER DEFAULT PRIVILEGES
testdb=> \c testdb user1
You are now connected to database "testdb" as user "user1".
testdb=> select * from shared_schema.t3;
ERROR: permission denied for relation t3
testdb=> \c testdb creator3
testdb=> create table shared_schema.t4 (c1 int);
CREATE TABLE
testdb=> \c testdb user1
You are now connected to database "testdb" as user "user1".
testdb=> select * from shared_schema.t4;
c1
----
(0 rows)
复制代码
上述代码第 3 行为当前用户在 shared_schema 下面创建的表的 select 权限授予 user1。第 7 行 user1 查询 shared_schema.t3 报权限不足,是因为 alter default privileges 只处理将来的对象。shared_schema.t3 在是之前创建的。我们新建表 shared_schema.t4,user1 用户查询正常。
如果要处理已有表的权限,使用 grant 语句。参见grant语法说明。
testdb=> \c testdb creator3
You are now connected to database "testdb" as user "creator3".
testdb=> grant select on all tables in schema shared_schema to user1;
ERROR: permission denied for relation t1
testdb=> grant select on table shared_schema.t3 to user1;
GRANT
testdb=> \c testdb user1
You are now connected to database "testdb" as user "user1".
testdb=> select * from shared_schema.t3;
c1
----
(0 rows)
复制代码
代码第 3 行中 shared_schema 中包含有 3 个用户创建的表,而 creator3 只是表 t3 的创建者(Owner)。所以授予整个 schema 的权限会报错,只授予 creator3 是 Owner 的表 t3 之后,user1 用户查询正常。
alter default privileges 只处理将来的对象,grant 只处理已有的对象。进一步的,这两种语法授予权限时涉及的对象仅包括 Owner 是当前用户的对象。如果要为共享 schema 下面所有 Owner 的对象授予权限,需要使用管理员用户使用 alter default privileges for user 语法和 grant 语法。
透明加密
透明加密的应用场景
透明加密能够保障用户数据安全。更换磁盘、磁盘流出或者运维非法直接读取磁盘文件会绕过认证、权限管理和审计,从而导致数据泄露的风险。客户对业务数据有很高机密性要求时建议使用透明加密。
透明加密的原理
透明加密功能是对存在硬盘上的用户数据加密存储,对用户及上层使用 SQL 的应用不感知。透明的含义是指对客户来说是无感知的,仅需要创建 GaussDB(DWS)集群时配置透明加密。目前支持行存表和列存表文件的加密存储,支持集群级别的透明加密配置。
集群级别的透明加密意味着集群中的所有库,库中的所有表都是加密存储。集群级别的透明加密还意味着需要在创建集群时进行配置,集群创建之后不可修改,既不能将非加密集群修改为加密集群,也不能将加密集群修改为非加密集群。
加密算法
透明加密核心是算法和密钥。我们采用 AES-128 算法,加密模式使用 CTR。CTR 流加密可以保证明文和密文长度相等,不会导致加密后数据存储空间膨胀。
密钥管理
使用华为公有云 KMS 服务管理,保证了用户的密钥安全。加密密钥层次结构有三层。按层次结构顺序排列,这些密钥为主密钥(CMK)、集群密钥 (CEK)、数据库密钥 (DEK)。
密钥轮转
出于安全考虑,用户可以执行密钥轮转操作。密钥轮转只轮转集群密钥,不论转数据库秘钥。
透明加密的后续演进
集群级透明加密的优点是所有数据包括用户表和系统表都加密,适用于所有加密需求。一枚硬币的两面性告诉我们,优点也可能是缺点。对所有数据库对象加密会对数据导入和查询带来性能上的开销。
为解决此问题,后续考虑支持细粒度透明加密。比如可以支持表级透明加密,用户在创建表时指定属性为加密表,该用户表的数据会加密存储。用户可以在包含敏感数据的表中开启加密属性,在查询和使用过程中不感知加解密过程。由于加密粒度较小,对性能的影响也较小。
透明加密是保障用户核心数据安全的有效手段。从使用场景和原理介绍了 GaussDB(DWS)数仓的透明加密特性,指出了后续透明加密特性的研究方向。
SQL 函数加密
技术背景
密码学中密码算法可以分为三类:哈希函数、对称密码算法和非对称密码算法。
哈希函数又称为摘要算法,对于数据 data,Hash 函数会生成固定长度的数据,即 Hash(data)=result。这个过程是不可逆的,即 Hash 函数不存在反函数,无法由 result 得到 data。在不应保存明文场景,比如口令(password)属于敏感信息,系统管理员用户也不应该知道用户的明文口令,就应该使用哈希算法,存储口令的单向哈希值。
实际使用中会加入盐值和迭代次数,避免相同口令生成相同的哈希值,以防止彩虹表攻击。
对称密码算法使用相同的密钥来加密和解密数据。对称密码算法分为分组密码算法和流密码算法。
分组密码算法将明文分成固定长度的分组,用密钥对每个分组加密。由于分组长度固定,当明文长度不是分组长度的整数倍时,会对明文做填充处理。由于填充的存在,分组密码算法得到的密文长度会大于明文长度。
流密码算法将明文逐比特与密钥流运算。流密码算法不需要填充,得到的密文长度等于明文长度。
非对称密码算法,又称为公钥密码算法。算法使用两个密钥:公钥和私钥。公钥向所有人公开,私钥保密。非对称密码算法应用于密钥协商、数字签名、数字证书等领域。
技术实现
GaussDB(DWS)主要提供了哈希函数和对称密码算法。哈希函数支持 sha256, sha384, sha512 和国密 sm3。对称密码算法支持 aes128, aes192, aes256 和国密 sm4。
哈希函数
将 string 使用 MD5 加密,并以 16 进制数作为返回值。MD5 的安全性较低,不建议使用。
以 hashmethod 算法对 hashstr 字符串进行信息摘要,返回信息摘要字符串。支持的 hashmethod:sha256, sha384, sha512, sm3。
testdb=# SELECT gs_hash('GaussDB(DWS)', 'sha256');
gs_hash
------------------------------------------------------------------
cc2d1b97c6adfba44bbce7386516f63f16fc6e6a10bd938861d3aba501ac8aab
(1 row)
复制代码
对称密码算法
gs_encrypt(encryptstr, keystr, cryptotype, cryptomode, hashmethod)
采用 cryptotype 和 cryptomode 组成的加密算法以及 hashmethod 指定的 HMAC 算法,以 keystr 为密钥对 encryptstr 字符串进行加密,返回加密后的字符串。支持的 cryptotype:aes128, aes192, aes256, sm4。支持的 cryptomode:cbc。支持的 hashmethod:sha256, sha384, sha512, sm3。
testdb=# SELECT gs_encrypt('GaussDB(DWS)', '1234', 'aes128', 'cbc', 'sha256');
gs_encrypt
--------------------------------------------------------------------------------------------------------------------------
AAAAAAAAAADlzZYiNQK1uB+p1gza4Lu3Moj3HdP4E1uJmqfDYBaXDLMt7RZoE0YVx9h2dMRYBQ5fhFNqqM49sUkeS72o8kX5vWRQvfW3fuocGyp+b+lX9A==
(1 row)
复制代码
采用 cryptotype 和 cryptomode 组成的加密算法以及 hashmethod 指定的 HMAC 算法,以 keystr 为密钥对 decryptstr 字符串进行解密,返回解密后的字符串。解密使用的 keystr 必须保证与加密时使用的 keystr 一致才能正常解密。
testdb=# SELECT gs_decrypt('AAAAAAAAAADlzZYiNQK1uB+p1gza4Lu3Moj3HdP4E1uJmqfDYBaXDLMt7RZoE0YVx9h2dMRYBQ5fhFNqqM49sUkeS72o8kX5vWRQvfW3fuocGyp+b+lX9A==', '1234', 'aes128', 'cbc', 'sha256');
gs_decrypt
--------------
GaussDB(DWS)
(1 row)
复制代码
效果分析
有个 student 表,有 id,name 和 score 三个属性。name 可以使用哈希函数加密保存,score 可以使用对称密码算法保存。
testdb=# create table student (id int, name text, score text);
CREATE TABLE
testdb=# insert into student values (1, gs_hash('alice', 'sha256'), gs_encrypt('95', '12345', 'aes128', 'cbc', 'sha256'));
INSERT 0 1
testdb=# insert into student values (2, gs_hash('bob', 'sha256'), gs_encrypt('92', '12345', 'aes128', 'cbc', 'sha256'));
INSERT 0 1
testdb=# insert into student values (3, gs_hash('peter', 'sha256'), gs_encrypt('98', '12345', 'aes128', 'cbc', 'sha256'));
INSERT 0 1
复制代码
没有密钥的用户即使拥有了 select 权限也无法看到 name 和 score 这两列加密数据。
testdb=# select * from student;
id | name | score
----+------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------
1 | 2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90 | AAAAAAAAAAB26RmKZdGciLdOM1Z0sjsHg6Qh1b8taF3cY5KDVm+faJK5AT9tjufkr3Wogj3tIpFfiIEb6+miGqPHWcmKnFsArAMoBG9pPDawGs1Qze7xGg==
2 | 81b637d8fcd2c6da6359e6963113a1170de795e4b725b84d1e0b4cfd9ec58ce9 | AAAAAAAAAAB26RmKZdGciLdOM1Z0sjsHZOHH7URkyme6r8Hfh1k0UsVbgbREjFMkgB52w+7GtUGqGgUik07ghajSD9PMIDLd/49wBCVROm2/HSOw6jzbxA==
3 | 026ad9b14a7453b7488daa0c6acbc258b1506f52c441c7c465474c1a564394ff | AAAAAAAAAAB26RmKZdGciLdOM1Z0sjsHwv6p/OAfDUyVULAqpaHIrYJYMcqLmQSj3K/REyavfMoKB7hgUpEPXfHRutWur37bru68jjt5XcBHFBjZeMgowA==
(3 rows)
复制代码
拥有密钥的用户可以通过解密查看到加密数据。
testdb=# select id, gs_decrypt(score, '12345', 'aes128', 'cbc', 'sha256') from student;
id | gs_decrypt
----+------------
1 | 95
2 | 92
3 | 98
(3 rows)
复制代码
总结
数据加密是防止未授权访问和防护数据泄露的有效技术。介绍了密码算法的基本原理和 GaussDB(DWS)数仓的加密函数,包括哈希函数 gs_hash,对称密码算法 gs_encrypt/gs_decrypt。举例说明了加密函数的使用场景。
想了解 GuassDB(DWS)更多信息,欢迎微信搜索“GaussDB DWS”关注微信公众号,和您分享最新最全的 PB 级数仓黑科技~
点击关注,第一时间了解华为云新鲜技术~
评论