天天看點

你應該知道的數倉安全

摘要:防止資料洩露可以有兩種技術路徑。一是權限管理,采用最小化授權原則對使用資料的使用者和應用程式授權。另一種是資料加密,包括使用SQL函數加密和透明加密。

前言

最近遇到一個客戶場景,涉及共享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 } [, ...]      

參數說明

  • target_role

已有角色的名稱。如果省略FOR ROLE/USER,則預設值為目前角色/使用者。

取值範圍:已有角色的名稱。

  • schema_name

現有模式的名稱。

target_role必須有schema_name的CREATE權限。

取值範圍:現有模式的名稱。

  • role_name

被授予或者取消權限角色的名稱。

取值範圍:已存在的角色名稱。

詳見​​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)。

  • 主密鑰儲存在KMS中,用于給CEK加密。
  • CEK用于加密DEK,CEK明文儲存在叢集記憶體中,密文儲存在服務管理面中。
  • DEK用于加密資料庫中的資料,DEK明文儲存在叢集記憶體中,密文儲存在服務管理面中。
你應該知道的數倉安全

密鑰輪轉

出于安全考慮,使用者可以執行密鑰輪轉操作。密鑰輪轉隻輪轉叢集密鑰,不論轉資料庫秘鑰。

透明加密的後續演進

叢集級透明加密的優點是所有資料包括使用者表和系統表都加密,适用于所有加密需求。一枚硬币的兩面性告訴我們,優點也可能是缺點。對所有資料庫對象加密會對資料導入和查詢帶來性能上的開銷。

為解決此問題,後續考慮支援細粒度透明加密。比如可以支援表級透明加密,使用者在建立表時指定屬性為加密表,該使用者表的資料會加密存儲。使用者可以在包含敏感資料的表中開啟加密屬性,在查詢和使用過程中不感覺加解密過程。由于加密粒度較小,對性能的影響也較小。

透明加密是保障使用者核心資料安全的有效手段。從使用場景和原理介紹了GaussDB(DWS)數倉的透明加密特性,指出了後續透明加密特性的研究方向。

SQL函數加密

技術背景

密碼學中密碼算法可以分為三類:哈希函數、對稱密碼算法和非對稱密碼算法。

  • 哈希函數

哈希函數又稱為摘要算法,對于資料data,Hash函數會生成固定長度的資料,即Hash(data)=result。這個過程是不可逆的,即Hash函數不存在反函數,無法由result得到data。在不應儲存明文場景,比如密碼(password)屬于敏感資訊,系統管理者使用者也不應該知道使用者的明文密碼,就應該使用雜湊演算法,存儲密碼的單向哈希值。

實際使用中會加入鹽值和疊代次數,避免相同密碼生成相同的哈希值,以防止彩虹表攻擊。

你應該知道的數倉安全
  • 對稱密碼算法

對稱密碼算法使用相同的密鑰來加密和解密資料。對稱密碼算法分為分組密碼算法和流密碼算法。

分組密碼算法将明文分成固定長度的分組,用密鑰對每個分組加密。由于分組長度固定,當明文長度不是分組長度的整數倍時,會對明文做填充處理。由于填充的存在,分組密碼算法得到的密文長度會大于明文長度。

流密碼算法将明文逐比特與密鑰流運算。流密碼算法不需要填充,得到的密文長度等于明文長度。

你應該知道的數倉安全
  • 非對稱密碼算法

非對稱密碼算法,又稱為公鑰密碼算法。算法使用兩個密鑰:公鑰和私鑰。公鑰向所有人公開,私鑰保密。非對稱密碼算法應用于密鑰協商、數字簽名、數字證書等領域。

你應該知道的數倉安全

技術實作

GaussDB(DWS)主要提供了哈希函數和對稱密碼算法。哈希函數支援sha256, sha384, sha512和國密sm3。對稱密碼算法支援aes128, aes192, aes256和國密sm4。

  • md5(string)

将string使用MD5加密,并以16進制數作為傳回值。MD5的安全性較低,不建議使用。

  • gs_hash(hashstr, hashmethod)

以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)      
  • gs_decrypt(decryptstr, keystr,cryptotype, cryptomode, hashmethod)

采用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級數倉黑科技~

繼續閱讀