1. 程式人生 > >SQL Server 2016 Always Encrypted(始終加密)

SQL Server 2016 Always Encrypted(始終加密)

Always Encrypted 功能旨在保護 Azure SQL Database 或 SQL Server 資料庫中儲存的敏感資料,如信用卡號或身份證號(例如美國社會安全號碼)。 始終加密允許客戶端對客戶端應用程式內的敏感資料進行加密,並且永遠不向 資料庫引擎 ( SQL Database 或 SQL Server)顯示加密金鑰。 因此,始終加密分隔了擁有資料(且可以檢視它)的人員與管理資料(但沒有訪問許可權)的人員。 始終加密確保本地資料庫管理員、雲資料庫操作員或其他高特權但未經授權的使用者無法訪問加密的資料,使客戶能夠放心地將敏感資料儲存在不受其直接控制的區域。 這樣,組織便可以靜態加密資料並利用 Azure 中的儲存,將本地資料庫的管理許可權委託給第三方,或者降低其自身 DBA 員工的安全核查要求。(更多參考:

始終加密(資料庫引擎)

常用客戶端對列加密的支援:

任務 SSMS PowerShell T-SQL
預配列主金鑰、列加密金鑰、加密列加密金鑰及其相應的列主金鑰。 使用者帳戶控制
在資料庫中建立金鑰元資料。 使用者帳戶控制 使用者帳戶控制
建立具有加密列的新表 使用者帳戶控制 使用者帳戶控制
對選定的資料庫列中的現有資料進行加密 使用者帳戶控制

限制也比較多。具有以下特徵的列不支援 Always Encrypted(例如,如果某個列存在以下任何情況,則不能在 CREATE TABLE/ALTER TABLE 中針對該列使用 Encrypted WITH 子句):

  • 使用以下任一資料型別的列: xml、 timestamp/rowversion、 image、 ntext、 text、 sql_variant、 hierarchyid、 geography、 geometry、別名、使用者定義型別。
  • FILESTREAM 列
  • 具有 IDENTITY 屬性的列
  • 具有 ROWGUIDCOL 屬性的列
  • 採用非 bin2 排序規則的字串(varchar、char 等)
  • 用作使用隨機加密列作為鍵列的非聚集索引的鍵的列(可以是確定性加密列)
  • 用作使用隨機加密列作為鍵列的聚集索引的鍵的列(可以是確定性加密列)
  • 用作包含隨機和確定性加密列的全文索引的鍵的列
  • 計算列引用的列(當表示式針對始終加密執行不受支援的操作時)
  • 稀疏列集
  • 統計資訊引用的列
  • 使用別名型別的列
  • 分割槽列
  • 包含預設約束的列
  • 使用隨機加密時 unique 約束引用的列(支援確定性加密)
  • 使用隨機加密時的主鍵列(支援確定性加密)
  • 使用隨機加密或確定性加密時引用外來鍵約束中的列(如果被引用和引用列使用不同的鍵或演算法)
  • check 約束引用的列
  • 使用變更資料捕獲的表中的列
  • 具有更改跟蹤的表中的主鍵列
  • 遮蔽的列(使用動態資料遮蔽)
  • Stretch Database 表中的列。 (無法為延伸啟用其列已使用始終加密加密的表。)
  • 外部 (PolyBase) 表中的列(注意:支援在同一查詢中使用外部表和列已加密的表)
  • 不支援針對加密列使用的表值引數。

不能對加密的列使用以下子句:

  • FOR XML
  • FOR JSON PATH

以下功能對加密的列不起作用:

  • 事務複製或合併複製
  • 分散式查詢(連結伺服器)

建立列主金鑰和列加密金鑰


--	建立列主金鑰
--	DROP COLUMN MASTER KEY [MasterKey_CurrentUser];
CREATE COLUMN MASTER KEY [MasterKey_CurrentUser]
WITH
(
	KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE',
	KEY_PATH = N'CurrentUser/My/53900F5E77EAB638B3D4BAE7428FC2CE1A8C660C'
)
GO

/* 
【KEY_STORE_PROVIDER_NAME】 取值:

金鑰儲存提供程式名稱		基礎金鑰儲存
---------------------		----------------------------------------------------
'MSSQL_CERTIFICATE_STORE'	Windows 證書儲存
'MSSQL_CSP_PROVIDER'		支援 Microsoft CryptoAPI 的儲存,如硬體安全模組 (HSM)。
'MSSQL_CNG_STORE'			支援下一代加密技術 API 的儲存,如硬體安全模組 (HSM)。
'Azure_Key_Vault'			請參閱 Azure Key Vault 入門


【KEY_PATH】 金鑰路徑格式及實際儲存位置(Windows 證書儲存):

證書儲存位置/證書儲存名稱/證書指紋 = N'CurrentUser/My/53900F5E77EAB638B3D4BAE7428FC2CE1A8C660C'

HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates\CA\Certificates\53900F5E77EAB638B3D4BAE7428FC2CE1A8C660C

執行:certmgr.msc   (certmgr ——>>個人——>> 證書)
*/


--	建立列加密金鑰
--	DROP COLUMN ENCRYPTION KEY [CEK01];
CREATE COLUMN ENCRYPTION KEY [CEK01]
WITH VALUES
(
	COLUMN_MASTER_KEY = [MasterKey_CurrentUser],
	ALGORITHM = 'RSA_OAEP',
	ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F00350033003900300030006600350065003700370065006100620036003300380062003300640034006200610065003700340032003800660063003200630065003100610038006300360036003000630013A0AAE50CCE337E01F9E1B8793BD966F4715BA7568B90EC2CD7096586553F77195EA083EAD694CA4F9D15E2734DCC14E73A4F308BDDBC273588EFAD91D761D1604DBF517A930CE062C5A3445F1ED66A24F38CDC8D68184176B1F0DD656288AA715B22B8AE3F73E1A1EDF58AE6FABE1479F726A0F8397BCF96E1CA3C982E1EC8B560961EBE2A0A05619B6BABDCCA61582A177BE8B9B3D1187D8B04FBC40C4CA1D14E43BEF6EFCEE83F2982750FFE07B2369C06F3122BE8406A26EC491FF11C83099CB6A34FA5B59CF33859A95DDF1C5251F2A92CBF8E9A3760B22F42F3CA2302C0CD7FEA3D6509A288B0023B087360D985D95EFEF21CF7D9D36212479168A1A67DB0BD8CDA3DC1F02500BF4D43A45AFB62DBA88DF7CA2E77AE3F74686F26F3C524CB088B93C6DB0D2C2D2B16464FD92879483370EDC1F83DEC082582321BDD1364B3BFF5ED1FA55D0CD76EE00C8219FD6DE6CD8B8371DADD4C20E8C26C4AEC5C4D26C5ACFBA86C736BB92CA5A14EDAB4C265D052A5484012B0B03ED851879F8B7453B0D65A7CE4D7C9D70E9F5DA78E39F53BE16E798C9C999B0BA9591E83A2B17E2E9E98A263988C52CA8E9058832B68F4AD7B84BE1E3FE3D63DE254EDDC54B07CABD10434BCA53B31E383DF337CE1B0EEA4D17243839723A7AC04AF94A08350EDC7C56A22E1A6C47D428EC7098E9590DD2CE931F194464F94385BDE6D90153D
)
GO

/*
--	可增加多個列加密金鑰
ALTER COLUMN ENCRYPTION KEY [CEK01]   
ADD VALUE   -- [ ADD | DROP ]
(  
	COLUMN_MASTER_KEY = [MasterKey_CurrentUser2], --不同的CMK
	ALGORITHM = 'RSA_OAEP',   
	ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F0064006500650063006200660034006100340031003000380034006200350033003200360066003200630062006200350030003600380065003900620061003000320030003600610037003800310066001DDA6134C3B73A90D349C8905782DD819B428162CF5B051639BA46EC69A7C8C8F81591A92C395711493B25DCBCCC57836E5B9F17A0713E840721D098F3F8E023ABCDFE2F6D8CC4339FC8F88630ED9EBADA5CA8EEAFA84164C1095B12AE161EABC1DF778C07F07D413AF1ED900F578FC00894BEE705EAC60F4A5090BBE09885D2EFE1C915F7B4C581D9CE3FDAB78ACF4829F85752E9FC985DEB8773889EE4A1945BD554724803A6F5DC0A2CD5EFE001ABED8D61E8449E4FAA9E4DD392DA8D292ECC6EB149E843E395CDE0F98D04940A28C4B05F747149B34A0BAEC04FFF3E304C84AF1FF81225E615B5F94E334378A0A888EF88F4E79F66CB377E3C21964AACB5049C08435FE84EEEF39D20A665C17E04898914A85B3DE23D56575EBC682D154F4F15C37723E04974DB370180A9A579BC84F6BC9B5E7C223E5CBEE721E57EE07EFDCC0A3257BBEBF9ADFFB00DBF7EF682EC1C4C47451438F90B4CF8DA709940F72CFDC91C6EB4E37B4ED7E2385B1FF71B28A1D2669FBEB18EA89F9D391D2FDDEA0ED362E6A591AC64EF4AE31CA8766C259ECB77D01A7F5C36B8418F91C1BEADDD4491C80F0016B66421B4B788C55127135DA2FA625FB7FD195FB40D90A6C67328602ECAF3EC4F5894BFD84A99EB4753BE0D22E0D4DE6A0ADFEDC80EB1B556749B4A8AD00E73B329C95827AB91C0256347E85E3C5FD6726D0E1FE82C925D3DF4A9  
); 
GO
--	刪除其中一個
ALTER COLUMN ENCRYPTION KEY [CEK01]  
DROP VALUE  
(  
    COLUMN_MASTER_KEY = [MasterKey_CurrentUser2]  
);  
GO
*/

-- 檢視(或開啟資料庫——>>安全性——>>Always Encrypted 金鑰)
select * from sys.column_master_keys
select * from sys.column_encryption_keys
select * from sys.column_encryption_key_values


--	更改資料庫排序規則
--	select * from ::fn_helpcollations() where name like 'Chinese%bin2'
ALTER DATABASE test COLLATE Latin1_General_BIN2;
GO

對已存在的表字段加密


--當前已存在的表,且有資料,結果如下:
CREATE TABLE [dbo].[tmp_ms_xx_Province1] (
    [ProvinceId]   INT              NOT NULL,
    [ProvinceName] NVARCHAR (60)  NOT NULL,
    [Alias] VARCHAR (10) NULL
);


--	原有的表字段加密前,先把欄位長度加長(注意!)
ALTER TABLE Province ALTER COLUMN ProvinceName NVARCHAR(1000);
GO

/*【更注意】加密當前表的欄位過程中,會把原來的表刪掉替換,如果有特殊作用需謹慎!加密過程如下:

--1.建立同名表
CREATE TABLE [dbo].[tmp_ms_xx_Province1] (
    [ProvinceId]   INT              NOT NULL,
    [ProvinceName] NVARCHAR (1000)  COLLATE latin1_general_BIN2  ENCRYPTED WITH (
     COLUMN_ENCRYPTION_KEY = [CEK01],
     ALGORITHM = N'AEAD_AES_256_CBC_HMAC_SHA_256',
     ENCRYPTION_TYPE = RANDOMIZED
    ) NULL,
    [Alias]        VARCHAR (10)     COLLATE Chinese_PRC_CI_AS NULL,
    [tceGuidCol1]  UNIQUEIDENTIFIER CONSTRAINT [tmp_ms_xx_constraint_tceGuidCol1_Province_dbo1] UNIQUE
);

--2.原表增加一個欄位 並 更新預設值
ALTER TABLE [dbo].[Province] ADD tceGuidCol1 UNIQUEIDENTIFIER;


--3.匯入主要欄位到新表
insert bulk [dbo].[tmp_ms_xx_Province1] ([ProvinceId] Int, [ProvinceName] VarBinary(2065), [tceGuidCol1] UniqueIdentifier) 
with (TABLOCK, FIRE_TRIGGERS)

--4.按guid更新資料到新表
UPDATE [dbo].[tmp_ms_xx_Province1]
SET    [dbo].[tmp_ms_xx_Province1].[Alias]   = [dbo].[Province].[Alias]
FROM   [dbo].[Province]
WHERE  [dbo].[Province].[tceGuidCol1] = [dbo].[tmp_ms_xx_Province1].[tceGuidCol1];


--5.刪除原表,更名新表
DROP TABLE [dbo].[Province];
EXECUTE sp_rename N'[dbo].[tmp_ms_xx_Province1]', N'Province';

--6.刪除之前新增的多餘欄位
ALTER TABLE [dbo].[Province] DROP CONSTRAINT [tmp_ms_xx_constraint_tceGuidCol1_Province_dbo1], COLUMN [tceGuidCol1];

*/


--	加密成功後檢視,該欄位都是加密字元。
SELECT * FROM Province

--	若要檢視解密內容,重新連線,連線選項中新增此引數:Column Encryption Setting=Enabled

--	連線進來後直接檢視,可看到明文資料
SELECT * FROM Province
SELECT * FROM Province WHERE ProvinceName = N'北京直轄市'


--	查詢和新增資料呢?? 這樣是報錯的!!!
SELECT * FROM Province WHERE ProvinceName = N'北京直轄市'
INSERT INTO Province(ProvinceId,ProvinceName,Alias) VALUES(35,N'測試' ,N'測試') --字元都使用Unicode
GO
/*
訊息 206,級別 16,狀態 2,第 143 行
運算元型別衝突: nvarchar 與 nvarchar(4000) encrypted with (encryption_type = 'DETERMINISTIC', 
encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK01', 
column_encryption_key_database_name = 'test') 不相容
*/


/*
那就用儲存過程中的引數插入吧!!兩個地方可設定當前連線的客戶端使用引數化:
查詢——>>查詢選項——>>執行——>>高階——>>勾選“啟用 Always Encrtpted 引數化”
工具——>>選項——>>執行查詢——>>SQL Server——>>高階——>>勾選“啟用 Always Encrtpted 引數化”
*/


--	查詢,正常!
DECLARE @ProvinceName NVARCHAR(60) = N'北京直轄市'
SELECT * FROM Province WHERE ProvinceName = @ProvinceName
GO

--	新增,正常!
DECLARE @ProvinceId INT = 35
DECLARE @ProvinceName NVARCHAR(60) = N'測試'
DECLARE @Alias VARCHAR(10) = N'測試'
INSERT INTO dbo.Province(ProvinceId,ProvinceName,Alias) VALUES (@ProvinceId,@ProvinceName ,@Alias)
GO
/* 以下兩種寫法則報錯(奇怪?):
DECLARE @ProvinceId INT
DECLARE @ProvinceName NVARCHAR(60) 
DECLARE @Alias VARCHAR(10)
SET @ProvinceId = 36
SET @ProvinceName = N'測試'
SET @Alias = N'測試'
INSERT INTO dbo.Province(ProvinceId,ProvinceName,Alias) VALUES (@ProvinceId,@ProvinceName ,@Alias)
GO
DECLARE @ProvinceId INT,@ProvinceName NVARCHAR(60) ,@Alias VARCHAR(10)
SET @ProvinceId = 35
SET @ProvinceName = N'測試'
SET @Alias = N'測試'
INSERT INTO dbo.Province(ProvinceId,ProvinceName,Alias) VALUES (@ProvinceId,@ProvinceName ,@Alias)
GO

訊息 33299,級別 16,狀態 6,第 183 行
加密方案不匹配列/變數 '@ProvinceName'。列/變數的加密方案為 (encryption_type = 'PLAINTEXT'),
行“9”附近的表示式預期其為 (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256'
, column_encryption_key_name = 'CEK01', column_encryption_key_database_name = 'test') (或更弱)。

*/

 SELECT * FROM Province

新表建立時進行欄位加密設定

--	DROP TABLE Customers
CREATE TABLE Customers (  
    CustName nvarchar(300) COLLATE  Latin1_General_BIN2 ENCRYPTED WITH (
			COLUMN_ENCRYPTION_KEY = CEK01,	-- CEK
			ENCRYPTION_TYPE = RANDOMIZED,		-- 隨機長度
			ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'),   
    SSN varchar(300) COLLATE  Latin1_General_BIN2 ENCRYPTED WITH (
			COLUMN_ENCRYPTION_KEY = CEK01,	-- CEK
			ENCRYPTION_TYPE = DETERMINISTIC ,	-- 固定長度
			ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'),   
    Age int NULL  
);  
GO 

DECLARE @CustName nvarchar(60) = N'Always Encrypted'
DECLARE @SSN varchar(11) = '198-33-0987'
DECLARE @Age int = 10
INSERT INTO dbo.Customers(CustName,SSN,Age) VALUES (@CustName,@SSN ,@Age)
GO

SELECT * FROM Customers
GO

若去掉連線引數:Column Encryption Setting=Enabled , 則查詢結果都為加密字元,加密欄位的DML 也不正常。