1. 程式人生 > 實用技巧 >Lambda表示式 -- 四大核心函式

Lambda表示式 -- 四大核心函式

摘要

從SQL Server 2005開始引入了列加密技術,實現一些關鍵、核心的隱私資料列資訊加密。本期月報是我們分享SQL Server安全系列專題的開篇:如何使用對稱祕鑰實現SQL Server列加密技術。

場景引入

在平日的生活中,我相信大家或多或少都經歷過廣告、推銷、詐騙電話的騷擾,不厭其煩,比如:“喂,您XXX的房子要不要考慮出售?XXX的樓盤您要不要考慮購買?”。

往往這個時候,我們會想,我的電話,手機號碼都是被誰,哪些途徑洩露出去呢?到底有沒有技術手段來儘量或最大限度的減少手機號碼的洩露呢?答案是肯定的,那就讓我們一起來看看在SQL Server資料庫中如何實現類似於手機號、身份證號、駕照號等關鍵資訊如何被加密儲存。

原理分析

為了避免枯燥的原理性解釋,我們用一句話、一張圖、以及簡單的實現方法,三個方面來介紹SQL Server資料庫列加密技術。

一句話解釋

一句話解釋SQL Server資料庫的列加密技術:是使用加密演算法,將表中關鍵欄位資訊列從明文變成密文,使得使用者資訊可以被嚴格保護,不被輕易獲取的技術。

一張圖解釋

從下面這張圖,我們可以清楚的看到SQL Server資料庫中的關鍵資訊列是如何被加密的:

圖片來自微軟官方網站

實現方法

要實現SQL Server資料庫列級別加密(本例中使用對稱祕鑰進行列加密方法,當然還有其他方法),我們需要:

建立例項級別的Master Key

建立資料庫級別Master Key

建立資料庫級別證書

建立資料庫級別對稱祕鑰

使用對稱祕鑰加密關鍵列資料

具體實現

以下是使用對稱祕鑰加密使用者手機號碼的具體實現步驟以及詳細過程。

建立測試資料庫

建立一個專門的測試資料庫,名為:TestDb。

--Step 1 - Create MSSQL sample database
USE master
GO
IF DB_ID('TestDb') IS NULL
	CREATE DATABASE [TestDb];
GO

建立測試表

在TestDb資料庫下,建立一張專門的測試表,名為:CustomerInfo。

--Step 2 - Create Test Table, init data & verify
USE [TestDb]
GO
IF OBJECT_ID('dbo.CustomerInfo', 'U') IS NOT NULL
	DROP TABLE dbo.CustomerInfo
CREATE TABLE dbo.CustomerInfo
(
CustomerId		INT IDENTITY(10000,1)	NOT NULL PRIMARY KEY,
CustomerName	VARCHAR(100)			NOT NULL,
CustomerPhone	CHAR(11)				NOT NULL
);

-- Init Table
INSERT INTO dbo.CustomerInfo 
VALUES ('CustomerA','13402872514')
,('CustomerB','13880674722')
,('CustomerC','13487759293')
GO

-- Verify data
SELECT * 
FROM dbo.CustomerInfo
GO

原始資料中,使用者的電話號碼為明文儲存,任何有許可權查看錶資料的使用者,都可以清楚明瞭的獲取到使用者的電話號碼資訊,展示如下:

建立例項級別Master Key

在SQL Server資料庫例項級別建立Master Key(在Master資料庫下,使用CREATE MASTER KEY語句):

-- Step 3 - Create SQL Server Service Master Key
USE master;
GO
IF NOT EXISTS(
	SELECT *
	FROM sys.symmetric_keys
	WHERE name = '##MS_ServiceMasterKey##')
BEGIN
	CREATE MASTER KEY ENCRYPTION BY 
	PASSWORD = 'MSSQLSerivceMasterKey'
END;
GO

建立資料庫級別Master Key

在使用者資料庫TestDb資料庫下,建立Master Key:

-- Step 4 - Create MSSQL Database level master key
USE [TestDb]
GO
IF NOT EXISTS (SELECT * 
				FROM sys.symmetric_keys 
				WHERE name LIKE '%MS_DatabaseMasterKey%')
BEGIN		
	CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'TestDbMasterKey@3*';
END
GO

建立資料庫級別證書

在測試資料庫TestDb下,建立證書,用於加密對稱祕鑰:

-- Step 5 - Create a Self Signed MSSQL Certificate:
USE [TestDb]
GO
IF NOT EXISTS(
	SELECT *
	FROM sys.certificates
	WHERE name = 'Cert_TestDb'
)
BEGIN
	CREATE CERTIFICATE Cert_TestDb
	AUTHORIZATION dbo
	WITH SUBJECT = 'Cert_TestDb to protect my phone',
	START_DATE = '08/10/2018',
	EXPIRY_DATE = '12/30/9999'
END
GO

我們強烈建議您備份您的證書到本地:

-- It's better to BACKUP your certificate to local disk.
USE [TestDb]
GO
BACKUP CERTIFICATE Cert_TestDb
TO FILE = 'C:\Temp\Cert_TestDb.cer';
GO

建立對稱祕鑰

在使用者資料庫下,建立對稱祕鑰,並使用證書對其進行加密:

-- Step 6 - Create MSSQL Symmetric Key
USE [TestDb]
GO
IF NOT EXISTS (SELECT * 
				FROM sys.symmetric_keys 
				WHERE name = 'SymKey_TestDb')
BEGIN
	CREATE SYMMETRIC KEY SymKey_TestDb 
	WITH ALGORITHM = AES_256 
	ENCRYPTION BY CERTIFICATE Cert_TestDb
	;
END
GO

檢視證書和對稱祕鑰

您可以使用如下查詢語句檢視對稱祕鑰以及證書:

USE [TestDb]
GO
SELECT *
FROM  sys.symmetric_keys

SELECT *
FROM sys.certificates

結果展示如下:

  

當然,您也可以用SSMS圖形介面來檢視證書和對稱祕鑰物件,方法是在使用者資料庫下,開啟Security => Certificates => Symmetric Keys,如下圖所示:

  

修改表結構

接下來,我們需要修改表結構,新增一個數據型別為varbinary(max)的新列,假設列名為EncryptedCustomerPhone ,用於儲存加密後的手機號碼密文。

-- Step 7 - Change your table structure
USE [TestDb]
GO 
ALTER TABLE CustomerInfo 
ADD EncryptedCustomerPhone varbinary(MAX) NULL
GO

新列資料初始化

新列新增完畢後,我們將表中歷史資料的使用者手機號CustomerPhone,加密為密文,並存儲在新欄位EncryptedCustomerPhone中。方法是開啟對稱祕鑰,然後使用EncryptByKey函式加密CustomerPhone列,如下語句所示:

-- Step 8 - init the encrypted data into the newly column
USE [TestDb]
GO 
-- Opens the symmetric key: SymKey_TestDb
OPEN SYMMETRIC KEY SymKey_TestDb
DECRYPTION BY CERTIFICATE Cert_TestDb;
GO
UPDATE A
SET EncryptedCustomerPhone = EncryptByKey (Key_GUID('SymKey_TestDb'), CustomerPhone)
FROM dbo.CustomerInfo AS A;
GO
-- Closes the symmetric key: SymKey_TestDb
CLOSE SYMMETRIC KEY SymKey_TestDb;
GO
-- Double check the encrypted data of the new column
SELECT * FROM dbo.CustomerInfo

查看錶中EncryptedCustomerPhone列的資料,已經變成CustomerPhone加密後的密文,如下展示:

檢視加密資料

手機號被加密為密文後,我們需要使用DecryptByKey函式將其解密為明文(解密前,需要開啟對稱祕鑰),讓我們嘗試看看能否成功解密EncryptedCustomerPhone欄位。

-- Step 9 - Reading the SQL Server Encrypted Data
USE [TestDb]
GO 
-- Opens the symmetric key: SymKey_TestDb
OPEN SYMMETRIC KEY SymKey_TestDb
DECRYPTION BY CERTIFICATE Cert_TestDb;
GO

-- Now, it's time to list the original phone, encrypted phone and the descrypted phone.
SELECT 
	*,
	DescryptedCustomerPhone = CONVERT(CHAR(11), DecryptByKey(EncryptedCustomerPhone))
FROM dbo.CustomerInfo;
 
-- Close the symmetric key
CLOSE SYMMETRIC KEY SymKey_TestDb;
GO

查詢語句執行結果如下,CustomerPhone和DescryptedCustomerPhone欄位資料內容是一模一樣的,因此加密和解密成功。

新增新資料

歷史資料加密解密後的資料保持一致,然後,讓我們看看新新增的資料:

-- Step 10 - What if we add new record to table.
USE [TestDb]
GO 
OPEN SYMMETRIC KEY SymKey_TestDb
DECRYPTION BY CERTIFICATE Cert_TestDb;
GO
-- Performs the update of the record
INSERT INTO dbo.CustomerInfo (CustomerName, CustomerPhone, EncryptedCustomerPhone)
VALUES ('CustomerD', '13880975623', EncryptByKey( Key_GUID('SymKey_TestDb'), '13880975623'));  

-- Close the symmetric key
CLOSE SYMMETRIC KEY SymKey_TestDb;
GO

更新資料手機號

接下來,我們嘗試更新使用者手機號:

-- Step 11 - So, what if we upadate the phone
USE [TestDb]
GO 
OPEN SYMMETRIC KEY SymKey_TestDb
DECRYPTION BY CERTIFICATE Cert_TestDb;

-- Performs the update of the record
UPDATE A
SET EncryptedCustomerPhone = EncryptByKey( Key_GUID('SymKey_TestDb'), '13880971234')
FROM dbo.CustomerInfo AS A
WHERE CONVERT(CHAR(11), DecryptByKey(EncryptedCustomerPhone)) = '13880975623'

-- Close the symmetric key
CLOSE SYMMETRIC KEY SymKey_TestDb;
GO

刪除手機號明文列

一切沒有問題,我們可以將使用者手機號明文列CustomerPhone刪除:

-- Step 12 - Remove old column
USE [TestDb]
GO 
ALTER TABLE CustomerInfo
DROP COLUMN CustomerPhone;
GO

再次檢查資料

再次嘗試解密密文欄位資料:

--Step 13 - verify again
USE [TestDb]
GO 
OPEN SYMMETRIC KEY SymKey_TestDb
DECRYPTION BY CERTIFICATE Cert_TestDb;

SELECT 
	*,
	DescryptedCustomerPhone = CONVERT(CHAR(11), DecryptByKey(EncryptedCustomerPhone))
FROM dbo.CustomerInfo
 
CLOSE SYMMETRIC KEY SymKey_TestDb;
GO

結果展示如下:

  

一切正常,歷史資料、新新增的資料、更新的資料,都可以工作完美。按理,文章到這裡也就結束。但是有一個問題我們是需要搞清楚的,那就是:如果我們新建立了使用者,他能夠訪問這個表的資料嗎?以及我們如何讓新使用者能夠訪問該表的資料呢?

新增新使用者

模擬新新增一個使用者EncryptedDbo:

-- Step 14 - Create a new user & access the encrypted data
USE [TestDb]
GO 
CREATE LOGIN EncryptedDbo
	WITH PASSWORD=N'EncryptedDbo@3*', CHECK_POLICY = OFF;
CREATE USER EncryptedDbo FOR LOGIN EncryptedDbo;

GRANT SELECT ON OBJECT::dbo.CustomerInfo TO EncryptedDbo;
GO

新使用者查詢資料

使用剛才建立的使用者,在SSMS中新開啟一個連線,查詢資料:

-- Step 15 -- OPEN a new connection query window using the new user and query data 
USE [TestDb]
GO

OPEN SYMMETRIC KEY SymKey_TestDb
DECRYPTION BY CERTIFICATE Cert_TestDb;

SELECT 
	*,
	DescryptedCustomerPhone = CONVERT(CHAR(11), DecryptByKey(EncryptedCustomerPhone))
FROM dbo.CustomerInfo

CLOSE SYMMETRIC KEY SymKey_TestDb;
GO

首先,新使用者無法OPEN SYMMETRIC KEY和CLOSE SYMMETRIC KEY,會報告如下異常:

其次,新使用者也無法解密EncryptedCustomerPhone,解密後的DescryptedCustomerPhone 欄位值為NULL,即新使用者無法檢視到使用者手機號明文,避免了未知使用者獲取使用者手機號等核心資料資訊。

為新使用者賦許可權

新使用者沒有檢視加密列資料的許可權,如果需要賦予許可權,方法如下:

--Step 16 - Grant permissions to EncryptedDbo
USE [TestDb]
GO

GRANT VIEW DEFINITION ON 
	SYMMETRIC KEY::[SymKey_TestDb] TO [EncryptedDbo];
	 
GRANT VIEW DEFINITION ON 
	CERTIFICATE::[Cert_TestDb] TO EncryptedDbo;
GO
GRANT CONTROL ON 
	CERTIFICATE::[Cert_TestDb] TO [EncryptedDbo];
GO

新使用者再次查詢

賦許可權完畢後,新使用者再次執行“新使用者查詢資料”中的查詢語句,已經可以正常獲取到加密列的明文資料了。展示如下:

最後總結

本文做為SQL Server安全系列文章開篇,介紹瞭如何使用對稱祕鑰實現列加密的詳細步驟和過程,實現關鍵資訊列加密,保護使用者核心資訊保安