日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MSSQL-最佳实践-Always Encrypted

發布時間:2024/8/23 数据库 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MSSQL-最佳实践-Always Encrypted 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

摘要

在SQL Server安全系列專題月報分享中,往期我們已經陸續分享了:如何使用對稱密鑰實現SQL Server列加密技術、使用非對稱密鑰實現SQL Server列加密、使用混合密鑰實現SQL Server列加密技術、列加密技術帶來的查詢性能問題以及相應解決方案、行級別安全解決方案、SQL Server 2016 dynamic data masking實現隱私數據列打碼技術和使用證書做數據庫備份加密這七篇文章,直接點擊以上文章前往查看詳情。本期月報我們分享SQL Server 2016新特性Always Encrypted技術。

問題引入

在云計算大行其道的如今,有沒有一種方法保證存儲在云端的數據庫中數據永遠保持加密狀態,即便是云服務提供商也看不到數據庫中的明文數據,以此來保證客戶云數據庫中數據的絕對安全呢?答案是肯定的,就是我們今天將要談到的SQL Server 2016引入的始終加密技術(Always Encrypted)。
使用SQL Server Always Encrypted,始終保持數據處于加密狀態,只有調用SQL Server的應用才能讀寫和操作加密數據,如此您可以避免數據庫或者操作系統管理員接觸到客戶應用程序敏感數據。SQL Server 2016 Always Encrypted通過驗證加密密鑰來實現了對客戶端應用的控制,該加密密鑰永遠不會通過網絡傳遞給遠程的SQL Server服務端。因此,最大限度保證了云數據庫客戶數據安全,即使是云服務提供商也無法準確獲知用戶數據明文。

具體實現

SQL Server 2016引入的新特性Always Encrypted讓用戶數據在應用端加密、解密,因此在云端始終處于加密狀態存儲和讀寫,最大限制保證用戶數據安全,徹底解決客戶對云服務提供商的信任問題。以下是SQL Server 2016 Always Encrypted技術的詳細實現步驟。

創建測試數據庫

為了測試方便,我們首先創建了測試數據庫AlwaysEncrypted。

--Step 1 - Create MSSQL sample database USE master GO IF DB_ID('AlwaysEncrypted') IS NULLCREATE DATABASE [AlwaysEncrypted]; GO-- Not 100% require, but option adviced. ALTER DATABASE [AlwaysEncrypted] COLLATE Latin1_General_BIN2;

創建列主密鑰

其次,在AlwaysEncrypted數據庫中,我們創建列主密鑰(Column Master Key,簡寫為CMK)。

-- Step 2 - Create a column master key USE [AlwaysEncrypted] GO CREATE COLUMN MASTER KEY [AE_ColumnMasterKey] WITH (KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE',KEY_PATH = N'CurrentUser/My/C3C1AFCDA7F2486A9BBB16232A052A6A1431ACB0' )GO

創建列加密密鑰

然后,我們創建列加密密鑰(Column Encryption Key,簡寫為CEK)。

-- Step 3 - Create a column encryption key USE [AlwaysEncrypted] GOCREATE COLUMN ENCRYPTION KEY [AE_ColumnEncryptionKey] WITH VALUES (COLUMN_MASTER_KEY = [AE_ColumnMasterKey],ALGORITHM = 'RSA_OAEP',ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F006300330063003100610066006300640061003700660032003400380036006100390062006200620031003600320033003200610030003500320061003600610031003400330031006100630062003000956D4610BE7DAEFC2E1B08D557BFF9E33FF23896BD76BB33A84560F5E4BE174D8798D86CC963BA57867404945B166D756CE87AFC9EB29EEB9E26B08115724C1724DCD449D0D14D4D5C4601A631899C733C7646EB845A816A17DB1D400B7C341C2EF5838731583B1C51A457E14692532FD7059B7F0AFF3D89BDF86FB3BB18880F6B49CD2EA6F346BA5EE130FCFCA69A71523722F824CD14B3CE2C29C9E46074F2FE36265450A0424F390C2BC32B724FAB674E2B58DB16347B842597AFEBE983C7F4F51BCC088292219BD6F6E1F092BD77C5AD80331770E0B0B8BF6428D2719560AF56780ECE8805F7B425818F31CF54C84FF11114DB693B6CB7D499B1490B8E155749329C9A7AF4417E2A17D0EACA92CBB59A4EE314C54BCD83F80E8D6363F9CF66D8608772DCEB5D3FF4C8A131E21984C2370AB0788E38CB330C1D6190A7513BE1179432705C0C38B9430FC7A8D10BBDBDBA4AC7A7E24D2E257A0B8B79AC2B6D7E0C2F2056F58579E96009C488F2C1C691B3DC9E2F5D538D2E96BB4E8DB280F3C0461B18ADE30A3A5C5279C6861E3109C8EEFE4BC8192338137BBF7D5BFD64A689689B40B5E1FB7A157D06F6674C807515255C0F124ED866D9C0E5294759FECFF37AEEA672EF5C3A7649CAA8B55288526DF6EF8EB2D7485601E9A72CFA53D046E200320BAAD32AD559C644018964058BBE9BE5A2BAFB28E2FF7B37C85B49680F )GO

檢查CMK和CEK

接下來,我們檢查下剛才創建的列主密鑰和列加密密鑰,方法如下:

-- Step 4 - CMK & CEK Checking select * from sys.column_master_keys select * from sys.column_encryption_keys select * from sys.column_encryption_key_values

一切正常,如下截圖所示:

當然,您也可以使用SSMS的IDE來查看Column Master Key和Column Encryption Key,方法是:
展開需要檢查的數據庫 -> Security -> Always Encrypted Keys -> 展開Column Master Keys和 Column Encryption Keys。如下圖所示:

創建Always Encryped測試表

下一步,我們創建Always Encrypted測試表,代碼如下:

-- Step 5 - Create a table with an encrypted columnUSE [AlwaysEncrypted] GO IF OBJECT_ID('dbo.CustomerInfo', 'U') IS NOT NULLDROP TABLE dbo.CustomerInfo GO CREATE TABLE dbo.CustomerInfo ( CustomerId INT IDENTITY(10000,1) NOT NULL PRIMARY KEY, CustomerName NVARCHAR(100) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = AE_ColumnEncryptionKey) NOT NULL, CustomerPhone NVARCHAR(11) COLLATE Latin1_General_BIN2ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = AE_ColumnEncryptionKey) NOT NULL) ; GO

在創建Always Encrypted測試表過程中,對于加密字段,我們指定了:
? 加密類型:DETERMINISTIC和RANDOMIZED。
? 算法:AEAD_AES_256_CBC_HMAC_SHA_256是Always Encrypted專有算法。
? 加密密鑰:創建的加密密鑰名字。

導出服務器端證書

最后,我們將服務端的證書導出成文件,方法如下:
Control Panel –> Internet Options -> Content -> Certificates -> Export。如下圖所示:

導出向導中輸入私鑰保護密碼。

選擇存放路徑。

最后導出成功。

應用程序端測試

SQL Server服務端配置完畢后,我們需要在測試應用程序端導入證書,然后測試應用程序。

客戶端導入證書

客戶端導入證書方法與服務端證書導出方法入口是一致的,方法是:Control Panel –> Internet Options -> Content -> Certificates -> Import。如下截圖所示:

然后輸入私鑰文件加密密碼,導入成功。

測試應用程序

我們使用VS創建一個C#的Console Application做為測試應用程序,使用NuGet Package功能安裝Dapper,做為我們SQL Server數據庫操作的工具。
注意:僅.NET 4.6及以上版本支持Always Encrypted特性的SQL Server driver,因此,請確保您的項目Target framework至少是.NET 4.6版本,方法如下:右鍵點擊您的項目 -> Properties -> 在Application中,切換你的Target framework為.NET Framework 4.6。

為了簡單方便,我們直接在SQL Server服務端測試應用程序,因此您看到的連接字符串是連接本地SQL Server服務。如果您需要測試遠程SQL Server,修改連接字符串即可。整個測試應用程序代碼如下:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Dapper; using System.Data; using System.Data.SqlClient;namespace AlwaysEncryptedExample {public class AlwaysEncrypted{public static readonly string CONN_STRING = "Column Encryption Setting = Enabled;Server=.,1433;Initial Catalog=AlwaysEncrypted;Trusted_Connection=Yes;MultipleActiveResultSets=True;";public static void Main(string[] args){List<Customer> Customers = QueryCustomerList<Customer>(@"SELECT TOP 3 * FROM dbo.CustomerInfo WITH(NOLOCK)");// there is no recordif(Customers.Count == 0){Console.WriteLine("************There is no record.************");string execSql = @"INSERT INTO dbo.CustomerInfo VALUES (@customerName, @cellPhone);";Console.WriteLine("************Insert some records.************");DynamicParameters dp = new DynamicParameters();dp.Add("@customerName", "CustomerA", dbType: DbType.String, direction: ParameterDirection.Input, size: 100);dp.Add("@cellPhone", "13402871524", dbType: DbType.String, direction: ParameterDirection.Input, size: 11);DoExecuteSql(execSql, dp);Console.WriteLine("************re-generate records.************");Customers = QueryCustomerList<Customer>(@"SELECT TOP 3 * FROM dbo.CustomerInfo WITH(NOLOCK)");}else{Console.WriteLine("************There are a couple of records.************");}foreach(Customer cus in Customers){Console.WriteLine(string.Format("Customer name is {0} and cell phone is {1}.", cus.CustomerName, cus.CustomerPhone));}Console.ReadKey();}public static List<T> QueryCustomerList<T>(string queryText){// input variable checkingif (queryText == null || queryText == ""){return new List<T>();}try{using (IDbConnection dbConn = new SqlConnection(CONN_STRING)){// if connection is closed, open itif (dbConn.State == ConnectionState.Closed){dbConn.Open();}// return the query result data set to list.return dbConn.Query<T>(queryText, commandTimeout: 120).ToList();}}catch (Exception ex){Console.WriteLine("Failed to execute {0} with error message : {1}, StackTrace: {2}.", queryText, ex.Message, ex.StackTrace);// return empty listreturn new List<T>();}}public static bool DoExecuteSql(String execSql, object parms){bool rt = false;// input parameters checkingif (string.IsNullOrEmpty(execSql)){return rt;}if (!string.IsNullOrEmpty(CONN_STRING)){// try to add event file targettry{using (IDbConnection dbConn = new SqlConnection(CONN_STRING)){// if connection is closed, open itif (dbConn.State == ConnectionState.Closed){dbConn.Open();}var affectedRows = dbConn.Execute(execSql, parms);rt = (affectedRows > 0);}}catch (Exception ex){Console.WriteLine("Failed to execute {0} with error message : {1}, StackTrace: {2}.", execSql, ex.Message, ex.StackTrace);}}return rt;}public class Customer{private int customerId;private string customerName;private string customerPhone;public Customer(int customerId, string customerName, string customerPhone){this.customerId = customerId;this.customerName = customerName;this.customerPhone = customerPhone;}public int CustomerId{get{return customerId;}set{customerId = value;}}public string CustomerName{get{return customerName;}set{customerName = value;}}public string CustomerPhone{get{return customerPhone;}set{customerPhone = value;}}}} }

我們在應用程序代碼中,僅需要在連接字符串中添加Column Encryption Setting = Enabled;屬性配置,即可支持SQL Server 2016新特性Always Encrypted,非常簡單。為了方便大家觀察,我把這個屬性配置放到了連接字符串的第一個位置,如下圖所示:

運行我們的測試應用程序,展示結果如下圖所示:

從應用程序的測試結果來看,我們可以正常讀、寫Always Encrypted測試表,應用程序工作良好。那么,假如我們拋開應用程序使用其它方式能否讀寫該測試表,看到又是什么樣的數據結果呢?

測試SSMS

假設,我們使用SSMS做為測試工具。首先讀取Always Encrypted測試表中的數據:

-- try to read Always Encrypted table and it'll show us encrypted data instead of the plaintext. USE [AlwaysEncrypted] GO SELECT * FROM dbo.CustomerInfo WITH(NOLOCK)

展示結果如下截圖:

然后,使用SSMS直接往測試表中插入數據:

-- try to insert records to encrypted table, will be fail. USE [AlwaysEncrypted] GO INSERT INTO dbo.CustomerInfo VALUES ('CustomerA','13402872514'),('CustomerB','13880674722') GO

會報告如下錯誤:

Msg 206, Level 16, State 2, Line 74 Operand type clash: varchar is incompatible with varchar(8000) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'AE_ColumnEncryptionKey', column_encryption_key_database_name = 'AlwaysEncrypted') collation_name = 'Chinese_PRC_CI_AS'

如下截圖:

由此可見,我們無法使用測試應用程序以外的方法讀取和操作Always Encrypted表的明文數據。

測試結果分析

從應用程序讀寫測試和使用SSMS直接讀寫Always Encrypted表的測試結果來看,用戶可以使用前者正常讀寫測試表,工作良好;而后者無法讀取測試表明文,僅可查看測試表的加密后的密文數據,加之寫入操作直接報錯。

測試應用源代碼

如果您需要本文的測試應用程序源代碼,請點擊下載。

最后總結

本期月報,我們分享了SQL Server 2016新特性Always Encrypted的原理及實現方法,以此來保證存儲在云端的數據庫中數據永遠保持加密狀態,即便是云服務提供商也看不到數據庫中的明文數據,以此來保證客戶云數據庫的數據絕對安全,解決了云數據庫場景中最重要的用戶對云服務提供商信任問題。


原文鏈接
本文為云棲社區原創內容,未經允許不得轉載。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的MSSQL-最佳实践-Always Encrypted的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。