【導讀】本文描述如何使用 IBM DB2 Universal Database Version (Unix & Windows) 中提供的新函數輕松地將數據加密集成到數據庫應用程序中。
多年來,數據庫已經能夠阻止未經授權的人看到其中的數據,這通常是通過數據庫管理器中的特權和權限來實現的。在當前的環境下,對存儲數據的保密的需求日益增長。這意味著即使 DBA 對表中的數據有完全的訪問權限,但是表中可能還有數據擁有者不希望任何其他人看到的某些信息。特別是對於基於 Web 的應用程序,這一問題就更加明顯了,在這種應用程序中,用戶輸入的數據(比如信用卡號)需要保存起來,以備同一用戶以後使用該應用程序。同時,用戶擁有者希望能夠確保任何其他人不能訪問這種數據。為了實現這種功能,DB2 內置了一些 SQL 函數,這些函數允許應用程序加密和解密數據。當將數據插入到數據庫中時,可以使用用戶提供的加密密碼對其加密。當檢索該數據的時候,必須提供相同的密碼才能解密數據。對於要多次使用同一個密碼的情況,可以使用一個賦值語句設置 ENCRYPTION PASSWord 值,並令其在某次連接期間內有效。
本文將描述這些 SQL 函數,並給出一些關於如何使用這些加密函數的例子。我們還將討論在關系數據庫中使用加密數據的設計和性能相關事項。
實現
下面顯示了這些新的 SQL 函數的簽名。在 DB2 文檔的 SQL Reference 部分中有更詳細的文檔。(為了確保對加密的數據使用正確的數據類型和長度,請務必閱讀 SQL Reference 中 ENCRYPT 函數下的“Table Column Definition”部分。)
Encrypt (StringDataToEncrypt, PasswordOrPhrase, PassWordHint)
Decrypt_Char(EncryptedData, PassWordOrPhrase)
GetHint(EncryptedData)
Set Encryption PassWord
用於對數據加密的算法是一個 RC2 分組密碼(block cipher),它帶有一個 128 位的密鑰。這個 128 位的密鑰是通過消息摘要從密碼得來的。加密密碼與 DB2 認證無關,僅用於數據的加密和解密。
這裡可以提供一個可選的參數 PasswordHint,這是一個字符串,可以幫助用戶記憶用於對數據加密的 PassWordOrPhrase。(例如,可以使用 'George' 作為記憶 'Washington'的提示。)
列級加密
列級加密(column level encryption)意味著對於一個給定列中的所有值都使用相同的密碼進行加密。這種類型的加密可以在視圖中使用,也可以在使用了一個公共密碼的情況下使用。當對一個或多個表中所有的行使用相同的密鑰時,ENCRYPTION PASSWord 專用寄存器將十分有用。
例 1:這個例子使用 ENCRYPTION PASSWord 值來保存加密密碼。它對雇員的社會保險號進行加密,並以經過加密的形式將其存儲在 EMP 表中。
create table emp (ssn varchar(124) for bit data);
set encryption passWord = 'Ben123';
insert into emp (ssn) values(encrypt('289-46-8832'));
insert into emp (ssn) values(encrypt('222-46-1904'));
insert into emp (ssn) values(encrypt('765-23-3221'));
select decrypt_char(ssn) from emp;
例 2:這個例子在結合使用視圖的情況下使用 ENCRYPTION PASSWord 值來保存加密密碼。下面的語句聲明了 emp 表的一個視圖:
create vIEw clear_ssn (ssn) as select decrypt_char(ssn) from emp;
在應用程序代碼中,我們將 ENCRYPTION PASSWord 設置為 'Ben123',現在可以使用 clear_ssn 視圖了。
set encryption passWord = 'Ben123';
select ssn from clear_ssn;
行-列(單元格)或 集合-列級加密
行-列(單元格)或 集合-列(Set-Column)級加密意味著在一個加密數據列內使用多個不同的密碼。例如,Web 站點可能需要保存客戶信用卡號(ccn)。在這個數據庫中,每個客戶可以使用他自己的密碼或短語來加密 ccn。
例 3:Web 應用程序收集關於客戶的用戶信息。這種信息包括客戶名稱(存儲在宿主變量 custname中)、信用卡號(存儲在宿主變量 cardnum中)和密碼(存儲在宿主變量 userpswd中)。應用程序像下面這樣執行客戶信息的插入操作。
insert into customer (ccn, name) values(encrypt(:cardnum, :userpswd), :custname)
當應用程序需要重新顯示某客戶的信用卡信息時,客戶要輸入密碼,同樣該密碼也要存儲在宿主變量 userpswd 中。之後,可以像下面這樣檢索該 ccn :
select decrypt_char(ccn, :userpswd) from customer where name = :custname;
例 4:這個例子使用提示來幫助客戶記憶他們的密碼。這裡使用與例 3 相同的應用程序,該應用程序將提示保存到宿主變量 pswdhint中。假設 userpswd 的值是 'Chamonix', pswdhint的值是 'Ski Holiday'。
insert into customer (ccn, name)
values(encrypt(:cardnum, :userpswd, :pswdhint), :custname)
如果客戶請求關於所使用的密碼的提示,可以使用下面的查詢。
select gethint(ccn) into :pswdhint from customer where name = :custname;
pswdhint的值被設置為"Ski Holiday"。
加密非字符值
數值和日期/時間數據類型的加密通過強制類型轉換得到間接的支持。非字符的 SQL 類型通過強制轉換為 "varchar" 或 "char",就可以被加密了。有關強制類型轉換的更多信息,請參閱 SQL 參考文檔中的 “Casting Between Data Types” 部分。
例 5:加密和解密 TIMESTAMP 數據時用到的強制類型轉換函數。
-- Create a table to store our encrypted value
create table etemp (c1 varchar(124) for bit data);
set encryption password 'next passWord';
-- Store encrypted timestamp
insert into etemp values encrypt(char(CURRENT TIMESTAMP));
-- Select & decrypt timestamp
select timestamp(decrypt_char(c1)) from etemp;
例 6:加密/解密 double 數據。
set encryption password 'next passWord';
insert into etemp values encrypt(char(1.11111002E5));
select double(decrypt_char(c1)) from etemp;
性能
加密,就其本質而言,會使大部分 SQL 語句慢下來。但是如果多加注意,多加判斷,還是可以將大量的額外開銷降至最低。而且,加密數據對於數據庫的設計有著很大的影響。通常,您需要對一個模式中的一些敏感數據元素進行加密,例如社會保險號、信用卡號、病人姓名,等等。而有些數據值就不是那麼適於加密了 -- 例如布爾值(true 和 false),或者其他的像整數 1 到 10 這樣的小型集合。這些值與列名一起很容易被猜出,因此需要判斷加密是否真的有用。
在某些情況下,對加密的數據創建索引是很好的主意。加密數據的正確匹配及連接將使用您創建的索引。由於加密數據實質上是二進制數據,因此對加密數據進行范圍檢查時需要掃描表。范圍檢查需要解密某一列在所有行的值,因此應該避免進行范圍檢查,至少也應該進行適當的調優。
下面的場景闡明了我們的討論。考慮一種常見的主從(master-detail)模式,程序員可以在很多項目中使用這種模式。我們將對雇員的社會保險號(ssn)實現列級加密。在主表 emp 和從表 empProject 中,ssn 將以加密的形式存儲。
例 5:加密和解密 TIMESTAMP 數據時用到的強制類型轉換函數。
-- Create a table to store our encrypted value
create table etemp (c1 varchar(124) for bit data);
set encryption password 'next passWord';
-- Store encrypted timestamp
insert into etemp values encrypt(char(CURRENT TIMESTAMP));
-- Select & decrypt timestamp
select timestamp(decrypt_char(c1)) from etemp;
例 6:加密/解密 double 數據。
set encryption password 'next passWord';
insert into etemp values encrypt(char(1.11111002E5));
select double(decrypt_char(c1)) from etemp;
性能
加密,就其本質而言,會使大部分 SQL 語句慢下來。但是如果多加注意,多加判斷,還是可以將大量的額外開銷降至最低。而且,加密數據對於數據庫的設計有著很大的影響。通常,您需要對一個模式中的一些敏感數據元素進行加密,例如社會保險號、信用卡號、病人姓名,等等。而有些數據值就不是那麼適於加密了 -- 例如布爾值(true 和 false),或者其他的像整數 1 到 10 這樣的小型集合。這些值與列名一起很容易被猜出,因此需要判斷加密是否真的有用。
在某些情況下,對加密的數據創建索引是很好的主意。加密數據的正確匹配及連接將使用您創建的索引。由於加密數據實質上是二進制數據,因此對加密數據進行范圍檢查時需要掃描表。范圍檢查需要解密某一列在所有行的值,因此應該避免進行范圍檢查,至少也應該進行適當的調優。
下面的場景闡明了我們的討論。考慮一種常見的主從(master-detail)模式,程序員可以在很多項目中使用這種模式。我們將對雇員的社會保險號(ssn)實現列級加密。在主表 emp 和從表 empProject 中,ssn 將以加密的形式存儲。