PostgreSQL數(shù)據(jù)庫加密方法

作為應用最廣泛的信息存儲和處理系統(tǒng),數(shù)據(jù)庫中存在大量敏感數(shù)據(jù),如何防止數(shù)據(jù)被竊取和篡改是重中之重。加密技術(shù)是提高數(shù)據(jù)庫安全的一個重要手段,在對數(shù)據(jù)庫中存儲數(shù)據(jù)進行加密時,需要結(jié)合它們的特點,對加密算法、加密粒度以及加密方式進行合理選擇。比如,在選擇加密算法時,對加密尤其是解密速度要求比較快,不能因為加/解密過程而導致系統(tǒng)性能大幅度下降。其次,應當支持靈活的加密粒度。根據(jù)用戶的需要,能夠選擇對數(shù)據(jù)庫、表、記錄、字段、數(shù)據(jù)項進行加密。同時,還應結(jié)合目前DBMS選擇適當加密方式。

但不是什么加密方法和方式都是適合數(shù)據(jù)庫的,在加密數(shù)據(jù)的同時,也會帶來一些相關(guān)問題,如果處理不好,不僅會降低數(shù)據(jù)庫的安全性,而且還會帶來其它如性能的影響。

本文簡要介紹和分析了在一個基于開源數(shù)據(jù)庫PostgreSQL的安全數(shù)據(jù)庫系統(tǒng)研究的基礎上,如何針對PostgreSQL數(shù)據(jù)庫的存儲數(shù)據(jù)的不同層次,對數(shù)據(jù)庫的文件(或表、頁)、記錄、字段等多個層次實現(xiàn)了加密。

數(shù)據(jù)庫不同加密粒度實現(xiàn)

按照PostgreSQL數(shù)據(jù)庫的結(jié)構(gòu)層次,數(shù)據(jù)庫的加密粒度可以分為相應的數(shù)據(jù)庫級、表級、記錄級、字段級和數(shù)據(jù)項級。根據(jù)不同的應用需要,選擇合適的加密粒度。

一、對整個數(shù)據(jù)庫加密

整個數(shù)據(jù)庫加密,就是對數(shù)據(jù)庫中所有的系統(tǒng)表、數(shù)據(jù)表、索引、視圖和存儲過程等進行加密處理。這種加密方法簡單快捷,只需對相應數(shù)據(jù)庫文件進行加密處理即可,對于企業(yè)或者用戶簡單的備份整個數(shù)據(jù)庫,可以采取這種操作方便加密粒度。但是,使用中的數(shù)據(jù)庫如果采用這種方法則會非常不合適,因為數(shù)據(jù)庫中的數(shù)據(jù)共享性高,會同時被多個用戶和應用訪問使用,即使只需要查詢一條記錄,也需要對整個數(shù)據(jù)庫進行解密,對系統(tǒng)性能會產(chǎn)生極大的影響。因此對此整個數(shù)據(jù)庫加密的方式我們不作過多的研究和討論。

二、 數(shù)據(jù)庫的表級(頁面)加密

安全數(shù)據(jù)庫將表分成兩大類,含加密字段的表和不含加密字段的表。對于加密的數(shù)據(jù)表則整個塊加密,否則不加密,且每塊使用一個密鑰。安全數(shù)據(jù)庫中,如果一個表中存放敏感數(shù)據(jù),那么這個表的每一個頁面的數(shù)據(jù)域在內(nèi)存中是明文,在外存中是密文。

表級加密的對象是數(shù)據(jù)庫中的表。與數(shù)據(jù)庫級加密比較,采用表級加密粒度,系統(tǒng)的查詢性能會有所改善,因為對于未加密表的查詢,與傳統(tǒng)查詢方法一樣,系統(tǒng)性能不會受到影響,對于加密表的查詢,只需要解密對應的加密表,而不要解密整個數(shù)據(jù)庫。在實行表級加密時,可以采用對存儲數(shù)據(jù)的磁盤塊(頁面)進行加密。這種方法與DBMS集成時,需要對DBMS內(nèi)部一些核心模塊進行修改,包括對詞法分析器、解釋器和查詢執(zhí)行器的修改,這里我們對開放源代碼的數(shù)據(jù)庫管理系統(tǒng)PostgreSQL的源碼進行修改。

1) 加解密數(shù)據(jù)結(jié)構(gòu)

加密函數(shù):

Char cipherpage(char *buffer,int size,BlockNumber blocknum, Relation reln);

解密函數(shù):

Char decipherpage(char *buffer,int size,BlockNumber blocknum, Relation reln);

輸入:

Buffer:加解密數(shù)據(jù)塊所在內(nèi)存緩沖區(qū);

Size:數(shù)據(jù)塊大小;

Blocknum:數(shù)據(jù)塊定位信息,需要寫入或讀出的數(shù)據(jù)塊;

Reln:記錄數(shù)據(jù)庫名,數(shù)據(jù)庫關(guān)系表,數(shù)據(jù)空間的信息;

返回值:

加解密成功后,返回數(shù)據(jù)塊所在的內(nèi)存緩沖區(qū)。

2) 加解密流程的實現(xiàn)

當DBMS將內(nèi)存中的頁面寫出到外存中時,首先查詢安全字典,如果需要加密存儲,則用安全字典中當前密鑰加密。在將數(shù)據(jù)從外存讀入內(nèi)存后,如果頁頭標識頁面是加密過的(由函數(shù)iscryptic()進行判斷),則取出相應的密鑰解密。加密時,只加密頁面中的數(shù)據(jù)域。這里也是由iscryptic()對進行讀寫的關(guān)系表進行判斷是否需要加解密,來對當前的數(shù)據(jù)塊進行加密或解密。解密時,當數(shù)據(jù)塊從外存讀入內(nèi)存時,如果頁頭標識頁面是加密過的,則從安全字典中取出相應的密鑰解密數(shù)據(jù)域。加解密的密鑰通過主密鑰和頁塊的ID計算得出。

我們跟蹤數(shù)據(jù)的寫入和讀入流程,找到寫入和讀出數(shù)據(jù)塊(block)的位置,對該數(shù)據(jù)塊進行加解密。

和對整個數(shù)據(jù)庫加密一樣,對數(shù)據(jù)庫進行表級加密實現(xiàn)方法簡單,但是加密的粒度較粗,一張表中會含有大量不需要加密的數(shù)據(jù),這樣也會導致效率低下。

三、使用TOAST技術(shù)實現(xiàn)字段加密

使用TOAST技術(shù),將加密的字段從原始的數(shù)據(jù)中分離出來,單獨存放。按照此種處理方案,同一個表中的明文密文存放在不同的文件或頁面中。

首先對TOAST (The Oversized-Attribute Storage Technique,超大尺寸字段存儲技術(shù))進行一個簡單的概述。

PostgreSQL 數(shù)據(jù)庫的頁面大小是固定的(通常是 8Kb),并且不允許行跨越多個頁面,因此不可能直接存儲非常大的字段值。為了突破這個限制,大的字段值被壓縮和/或打碎成多個物理行。(這些事情對用戶都是透明的)。這個技術(shù)的昵稱是 TOAST("切片面包之后最好的東西")。TOAST 代碼只有在準備向某表中存儲超過 BLCKSZ/4 字節(jié)(通常是 2KB)的行的時候才會觸發(fā)。TOAST 代碼將在對應于主表的TOAST表中壓縮和/或另存字段值,直到數(shù)值比 BLCKSZ/4 字節(jié)短,或者無法得到更好的結(jié)果的時候才停止。

1)字段加密的實現(xiàn)

借助于TOAST技術(shù)我們可以將TOAST 代碼的觸發(fā)時機移植到當需要對某一數(shù)據(jù)庫表的字段進行加密時。這樣主表中需要加密的字段中只是存儲實際已經(jīng)加密的字段數(shù)據(jù)所在位置的索引值,實現(xiàn)的關(guān)鍵技術(shù)就是學習TOAST技術(shù),這是實現(xiàn)的難點。

需要加密字段的數(shù)據(jù)在這里不是被分裂成(壓縮后)固定字節(jié)的塊后被存儲到相應的TOAST表中,而是每個被加密后的字段數(shù)據(jù)塊都作為獨立的行在TOAST表里為所屬主表存儲。每個TOAST 表都有chunk_id字段(一個表示特定TOAST值的OID)、chunk_seq(一個序列號,存儲該塊在數(shù)值中的位置)、chunk_data(該塊實際的數(shù)據(jù))。在chunk_id 和chunk_seq上有一個唯一索引,提供對數(shù)值的快速檢索。因此,一個表示線外 TOAST 值的指針數(shù)據(jù)需要存儲要查閱的 TOAST 的OID和特定數(shù)值的OID(它的chunk_id)。這樣在主表中依據(jù)這些標識就可以順利找到被加密的字段,解密后即可使用。

TOAST 過的字段的大體積數(shù)值只是在把結(jié)果集發(fā)送給客戶端的時候才抽出來。因此,主表要小得多,并且它的大部分行都存儲在共享緩沖區(qū)里,因此就可以不需要任何線外存儲。排序集也縮小了,并且排序?qū)⒏嗟卦趦?nèi)存里完成。TOAST 表存儲將近一半大小的裸數(shù)據(jù),而主表只包含全部數(shù)據(jù)的 10%,這與在一個非 TOAST 的表對比起來,沒有任何運行時的區(qū)別。因此我們不必擔心TOAST帶來性能上的影響。

與前面幾種數(shù)據(jù)庫加密方法不同,對數(shù)據(jù)庫進行字段加密不需要對所有的數(shù)據(jù)進行加密,加密的粒度更小,對于不需要訪問到的記錄,完全不需要進行任何操作,所以使用起來效率會高一些。但是由于每一個字段都必須有一個密鑰與之匹配,因此產(chǎn)生和管理記錄密鑰比較復雜。以記錄為單位的加密分析與以字段為單位的加密情況相似。這里就不再進行敘述。

四、其他方式

在PostgreSQL數(shù)據(jù)庫中,所有的記錄都被構(gòu)造成一個TUPLE。在構(gòu)造的過程中,將加密列上的屬性進行加密,保障內(nèi)存中的數(shù)據(jù)是加密的,當一條記錄被引用時根據(jù)TUPLE中的標識對其相應的字段進行解密。

本文基于PostgreSQL數(shù)據(jù)庫自身特點簡要討論了幾種數(shù)據(jù)庫不同加密粒度式,用戶根據(jù)應用場合的不同, 可分別選用以數(shù)據(jù)庫表、記錄、字段作為加密基本單位的方案。由于層次不同, 這三個方案的適用環(huán)境與實現(xiàn)難度各不相同。一般而言, 加密單位越小, 適用范圍越廣, 但實現(xiàn)時的困難也越大。而數(shù)據(jù)庫的安全性仍然不斷面臨新的安全技術(shù)挑戰(zhàn),這有待我們?nèi)ミM一步解決。

知識點:

PostgreSQL是一個包含關(guān)系模型和支持SQL標準查詢語言的DBMS(數(shù)據(jù)庫管理系統(tǒng))。