SQL Server 2016 始終加密:易於實施,難以破解
已發表: 2022-03-11數據是任何公司的關鍵資產,尤其是包含財務或健康記錄等商業機密的交易數據。 數據在存儲它的服務器和請求它的客戶端之間傳輸時最容易受到攻擊。
確保安全的標準方法是加密服務器上的數據並使用啟用 SSL 的 HTTPS 協議來保護傳輸中的數據。 但是,如果我們可以進一步提高安全級別,通過使用 HTTPS 並通過通信線路以加密格式發送數據,只對擁有有效證書的客戶端上的數據進行解密呢? 這種方法將使傳統的中間人 (MITM) 攻擊變得更加困難。
Microsoft 對此問題的解決方案是始終加密,這是一種通過管道發送加密數據並僅由有權訪問有效證書的用戶解密的方法。 因此,即使攻擊者獲得了數據,如果沒有在客戶端計算機上存儲適當的證書,數據也將毫無用處。
本文介紹如何設置和使用 Always Encrypted,建議通過公共通信線路發送重要數據的任何人閱讀,即使他們使用 SSL 保護。
始終加密背後的概念
Always Encrypted 是 Microsoft 在 SQL Server 2016 中引入的一種客戶端加密技術。Always Encrypted 不僅在寫入數據時自動加密數據,而且在被批准的應用程序讀取數據時也會自動加密。 與實時加密磁盤上的數據和日誌文件但允許任何查詢數據的應用程序讀取數據的透明數據加密不同,Always Encrypted 要求您的客戶端應用程序使用啟用 Always Encrypted 的驅動程序與數據庫。 通過使用此驅動程序,應用程序將加密數據安全地傳輸到數據庫,然後只能由有權訪問加密密鑰的應用程序解密。 查詢數據的任何其他應用程序也可以檢索加密值,但該應用程序不能在沒有加密密鑰的情況下使用數據,從而使數據無用。 由於這種加密體系結構,SQL Server 實例永遠不會看到數據的未加密版本。
目前,唯一啟用 Always Encrypted 的驅動程序是用於 SQL Server 的 .NET Framework 數據提供程序,它需要在客戶端計算機上安裝 .NET Framework 4.6 版,以及 JDBC 6.0 驅動程序。 這可能會及時改變,但這些是截至 2017 年 4 月的官方 Always Encrypted 要求。
但我們為什麼需要這項技術? 應該使用 Always Encrypted 有幾個很好的理由:
- 安全性——數據始終需要安全。 現在 SSL 受到威脅,Always Encrypted 用另一層傳輸管道保護填補了空白。
- 監管支持——數據需要加密,並防止 DBA 被越來越多的行業監管(主要是金融和電信行業)窺探。 這在 PII 標準(“個人身份信息”)中有所描述,該標準規定必須保護信用卡號、社會保險號、姓名和地址等信息,否則數據所有者可能會受到嚴厲處罰。
如何使用始終加密
使用 Always Encrypted 需要在存儲加密表的數據庫服務器中進行少量準備工作。 準備工作分為兩步:
- 創建列主鍵定義
- 創建列加密密鑰
列主鍵
那麼什麼是列主鍵?
列主密鑰是存儲在 Windows 證書存儲中的證書(在演示中用作證書存儲選項),第三方硬件安全模塊(用於安裝、管理和使用的第三方解決方案的通用名稱證書)或 Azure Key Vault(Microsoft 的基於雲的證書管理解決方案)。
加密數據的應用程序使用列主密鑰來保護處理數據庫表列中數據加密的各種列加密密鑰。 使用來自 SQL Server 的證書存儲(有時稱為Enterprise Key Manager )需要使用 SQL Server Enterprise Edition。
在本文中,我們描述了存儲在 Windows 操作系統的 Microsoft 證書存儲中的自簽名證書的使用。 雖然這種方法不是最佳配置,但它展示了始終加密的概念——但還需要說明的是,這種方法對於生產環境是不可接受的,在生產環境中,證書管理必須使用單獨的、安全的用戶帳戶進行,最好是,在不同的服務器上。
您可以使用 SQL Server Management Studio (SSMS) 中的圖形界面或使用 T-SQL 創建列主鍵定義。 在 SSMS 中,連接到要在其中使用 Always Encrypted 保護數據庫表的 SQL Server 2016 數據庫實例。
創建和使用列主鍵
在對象資源管理器中,首先導航到數據庫,然後導航到 Security,然後展開 Always Encrypted Keys 文件夾以顯示其兩個子文件夾,如下圖所示:
要創建列主密鑰,請右鍵單擊Column Master Keys
文件夾並選擇New Column Master Key
。 在“ New Column Master Key
對話框中,鍵入列主密鑰的名稱,指定是將密鑰存儲在當前用戶或本地計算機的證書存儲區還是 Azure Key Vault 中,然後在列表中選擇一個證書。 如果沒有證書,或者如果您想使用新的自簽名證書,請單擊“ Generate Certificate
”按鈕,然後單擊“ OK
”。 此步驟創建一個自簽名證書並將其加載到運行 SSMS 的當前用戶帳戶的證書存儲中。
注意:您應該在受信任的計算機上執行這些步驟,而不是在託管 SQL Server 實例的計算機上。 這樣,即使主機計算機受到威脅,數據仍會在 SQL Server 中受到保護。
因此,在創建證書並將其配置為列主密鑰後,您必須將其導出並分發到託管需要訪問數據的客戶端的所有計算機。 如果客戶端應用程序是基於 Web 的,您必須在 Web 服務器上加載證書。 如果它是安裝在用戶計算機上的應用程序,那麼您必須將證書單獨部署到每個用戶的計算機上。
您可以在以下 URL 找到有關為您的操作系統導出和導入證書的適用說明:
- 導出證書
- Windows 7 和 Windows Server 2008 R2
- Windows 8 和 Windows Server 2012
- Windows 8.1 和 Windows Server 2012 R2
- Windows 10 和 Windows Server 2016
- 導入證書
- Windows 7 和 Windows Server 2008 R2
- Windows 8 和 Windows Server 2012
- Windows 8.1 和 Windows Server 2012 R2
- Windows 10 和 Windows Server 2016
當您將證書導入具有加密和解密數據的應用程序的計算機上的證書存儲區時,您必須將證書導入到計算機證書存儲區或運行該應用程序的域帳戶的證書存儲區。
列加密密鑰
創建列主密鑰後,您就可以為特定列創建加密密鑰了。 SQL Server 2016 ADO.NET 驅動程序使用列加密密鑰在將數據發送到 SQL Server 之前對其進行加密,並在從 SQL Server 2016 實例檢索數據後解密數據。 與列主密鑰一樣,您可以使用 T-SQL 或 SSMS 創建列加密密鑰。 雖然使用 T-SQL 更容易創建列主密鑰,但使用 SSMS 更容易創建列加密密鑰。
要創建列加密密鑰,請使用Object Explorer
連接到數據庫實例,導航到數據庫,然後導航到Security
,然後展開Always Encrypted Keys
文件夾。 右鍵單擊Column Encryption Keys
,然後選擇New Column Encryption Key
。 在“ New Column Encryption Key
對話框中,鍵入新加密密鑰的名稱,在下拉列表中選擇“ Column Master Key Definition
”,然後單擊“ OK
”。 您現在可以在新表的定義中使用列加密密鑰。

創建具有加密值的表
創建列主密鑰定義和列加密密鑰後,您可以創建一個表來保存加密值。
在執行此操作之前,您必須確定要使用的加密類型、要加密的列以及是否可以索引這些列。 使用Always Encrypted功能,您可以正常定義列大小,SQL Server 根據加密設置調整列的存儲大小。 創建表後,您可能需要更改應用程序以使用Always Encrypted在此表上執行命令。
SQL Server 2016 加密類型
在創建包含加密值的表之前,您必須決定是否應加密每一列。
首先,該列將用於查找值還是僅返回這些值?
如果該列將用於查找,則該列必須使用確定性加密類型,它允許相等操作。 但是,搜索已使用Always Encrypted功能加密的數據存在限制。 SQL Server 2016 僅支持相等操作,包括equal to
、 not equal to
、 joins
(使用相等)以及使用GROUP BY
子句中的值。 不支持使用LIKE
進行任何搜索。 此外,必須在應用程序級別對使用Always Encrypted 加密的數據進行排序,因為 SQL Server 將根據加密值而不是解密值進行排序。
如果該列不用於定位記錄,則該列應使用隨機加密類型。 這種類型的加密更安全,但它不支持搜索、連接或分組操作。
創建包含加密列的表
創建表時,您可以使用普通的CREATE TABLE
語法和列定義中的一些附加參數。 CREATE TABLE
語句的ENCRYPTED WITH
語法中使用了三個參數。
其中第一個是ENCRYPTION_TYPE
參數,它接受RANDOMIZED
或DETERMINISTIC
的值。 第二個是ALGORITHM
參數,它只接受RAEAD_AES_256_CBC_HMAC_SHA_256
的值。 第三個參數是COLUMN_ENCRYPTION_KEY
,它是您用來加密值的加密密鑰。
CREATE TABLE [dbo].[Customers] ( [CustomerId] [int] IDENTITY(1,1), [TaxId] [varchar](11) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = YOUR_COLUMN_ENCRYPTION_KEY) NOT NULL, [FirstName] [nvarchar](50) NULL, [LastName] [nvarchar](50) NULL, [MiddleName] [nvarchar](50) NULL, [Address1] [nvarchar](50) NULL, [Address2] [nvarchar](50) NULL, [Address3] [nvarchar](50) NULL, [City] [nvarchar](50) NULL, [PostalCode] [nvarchar](10) NULL, [State] [char](2) NULL, [BirthDate] [date] ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = YOUR_COLUMN_ENCRYPTION_KEY) NOT NULL PRIMARY KEY CLUSTERED ([CustomerId] ASC) ON [PRIMARY] ); GO
始終加密的索引
包含加密數據的列可以用作索引中的鍵列,前提是這些列是使用DETERMINISTIC
加密類型加密的。 當您嘗試在這些列上創建索引時,使用RANDOMIZED
加密類型加密的列會返回錯誤消息。 使用任一加密類型加密的列可以用作非聚集索引中的INCLUDE
列。
由於加密值可以是索引,因此對於使用 Always Encrypted 加密的值,除了您通常執行的索引和調整之外,不需要額外的性能調整措施。 額外的網絡帶寬和更大的 I/O 是返回值大小增加的唯一副作用。
始終加密的性能
性能始終是一個關鍵因素,尤其是在這種情況下,當我們將加密開銷添加到通常的數據庫流量中時。 測試性能的最佳站點是 SQL Performance,它測試了各種場景下的查詢執行和磁盤使用情況:
由於需要在加密和解密過程中執行 CPU 和硬盤驅動器工作,因此對使用的存儲空間量和查詢持續時間有明顯影響。 由於這會影響您的環境(CPU、RAM 和磁盤功能),您應該測試這是否會在生產中出現問題。
注意:如果您想了解有關 Microsoft SQL Server 性能優化的更多信息,請查看我們之前的一篇文章,如何調整 Microsoft SQL Server 以提高性能。
應用程序更改
您需要做什麼才能在遺留代碼中正確實現 Always Encrypted?
SQL Server 2016 的 Always Encrypted 功能的優點之一是,已經使用存儲過程、ORM 或參數化 T-SQL 命令的應用程序不需要更改應用程序即可使用 Always Encrypted,除非已經使用了非相等操作。 在應用程序中將 SQL 語句構建為動態 SQL 並直接對數據庫執行這些命令的應用程序需要修改以使用其查詢的參數化,這是所有應用程序的推薦安全最佳實踐,然後才能利用 Always Encrypted 功能。
使 Always Encrypted 工作所需的另一項更改是在連接到數據庫的應用程序的連接字符串中添加了一個連接字符串屬性: Column Encryption Setting=enabled
。
將此設置添加到連接字符串後,ADO.NET 驅動程序會詢問 SQL Server 正在執行的命令是否包含任何加密列,如果包含,則詢問哪些列已加密。 對於高負載應用程序,使用此設置可能不是最佳實踐,尤其是在大部分執行命令不包含加密值的情況下。
因此,.NET Framework 在 SqlConnection 對像上提供了一個名為SqlCommandColumnEncryptionSetting
的新方法,它具有三個可能的值:
-
Disabled
— 沒有 Always Encrypted 列或參數可用於使用此連接對象執行的查詢。 - 已
Enabled
— 對於使用此連接對象執行的查詢,存在始終加密的列和/或參數。 -
ResultSet
— 沒有 Always Encrypted 參數。 但是,使用此連接對象執行查詢會返回使用 Always Encrypted 加密的列。
注意:請注意,使用此方法可能需要對您的應用程序代碼進行大量更改。 另一種方法是重構您的應用程序以使用不同的連接。
為獲得 SQL Server 的最佳性能,明智的做法是只為使用 Always Encrypted 的查詢請求有關 Always Encrypted 的元數據。 這意味著在大部分查詢使用 Always Encrypted 的應用程序中,應啟用連接字符串,並且應用程序中的特定查詢應將SqlCommandColumnEncryptionSetting
指定為Disabled
。 對於大多數查詢不使用 Always Encrypted 值的應用程序,不應啟用連接字符串,並且應根據需要為使用 Always Encrypted 列的查詢設置SqlCommandColumnEncryptionSetting
為Enabled
或ResultSet
。 在大多數情況下,應用程序可以簡單地啟用連接字符串屬性,並且在使用加密數據時應用程序性能將保持不變。
始終加密是否值得努力?
簡短的回答? 當然是!
它不僅有助於防止許多潛在的安全問題,並為 SQL 開發人員提供附加的安全功能,而且還使您的系統更加合規,這在電信、銀行和保險等多個行業中至關重要。 同樣重要的是要注意,鑑於本文中提到的技術先決條件, Always Encrypted 可以通過對現有系統的最小應用程序更改來實現。
儘管您可以使用自定義解決方案來獲得相同的效果,但該技術與新版本的 SQL Server 捆綁在一起,並且可以開箱即用。 還需要注意的是,由於這是一項新技術,它的使用仍然存在一些限制,並且它增加了一些額外的硬件缺陷。
但是,除非它們會破壞您的環境,並且您的應用程序分佈在公司的 Intranet 之外,否則幾乎沒有理由不使用 Always Encrypted。