2017-04-05 52 views
1

我想通過始終加密來加密現有數據庫列。我的項目是一個ASP.NET項目,首先使用代碼,數據庫是SQL Server。數據庫已經有數據。我創建了一個遷移來實現我的目標。從解密列更新總是加密列

首先,我嘗試改變列的類型,使用以下內容。

ALTER TABLE [dbo].[TestDecrypted] ALTER COLUMN [FloatCol] [float] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL 

我得到以下錯誤。

Operand type clash: float is incompatible with float encrypted with (encryption_type = 'RANDOMIZED', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'TestEncrypt') 

然後我決定創建另一列並遷移數據。

ALTER TABLE [dbo].[TestDecrypted] ADD [FloatCol2] [float] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL 
UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = [FloatCol] 

而且我得到了同樣的錯誤。

我看着this後,我發現它可以插入數據,如以下

DECLARE @floatCol FLOAT = 1.1 
UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = @floatCol 

但是,如果我嘗試獲得從現有列中的值,它失敗。

DECLARE @floatCol FLOAT = (SELECT TOP 1 FloatCol FROM TestDecrypted) 
UPDATE [dbo].[TestDecrypted] SET FloatCol2 = @floatCol 

錯誤如下。

Encryption scheme mismatch for columns/variables '@floatCol'. The encryption scheme for the columns/variables is (encryption_type = 'PLAINTEXT') and the expression near line '4' expects it to be (encryption_type = 'RANDOMIZED', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'TestEncrypt'). 

有誰知道我該如何實現我的目標?


更新1

@尼基爾 - Vithlani微軟做了一些有趣的建議。

  • 始終加密嚮導在SSMS - 我想實現我的代碼首先遷移目標,所以這個想法不適合。
  • SqlBulkCopy - 它不適用於遷移,因爲新列將只在所有'Up'方法運行後才存在。因此我們不能在這個方法內以這種方式將數據插入到這個列中。

無論如何,他的建議驅使我到另一個嘗試:獲得解密的值,並與他們更新加密列。

var values = new Dictionary<Guid, double>(); 

var connectionString = ConfigurationManager.ConnectionStrings["MainDb"].ConnectionString; 
using (var sourceConnection = new SqlConnection(connectionString)) 
{ 
    var myCommand = new SqlCommand("SELECT * FROM dbo.TestDecrypted", sourceConnection); 
    sourceConnection.Open(); 

    using (var reader = myCommand.ExecuteReader()) 
    { 
     while (reader.Read()) 
     { 
      values.Add((Guid)reader["Id"], (double)reader["FloatCol"]); 
     } 
    } 
} 

Sql("ALTER TABLE [dbo].[TestDecrypted] ADD [FloatCol2] [float] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL"); 

foreach (var valuePair in values) 
{ 
    // The error occurs here 
    Sql([email protected]"DECLARE @value FLOAT = {valuePair.Value} 
UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = @value WHERE Id = '{valuePair.Key}'"); 
} 

實際上,我沒有嘗試創建另一列並遷移數據,如上面的示例中所述。我只在SSMS上試過。 現在我得到了一個不同的錯誤。

Transaction (Process ID 57) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. 

我試圖做到這一點,而沒有加密新列,它工作正常。

任何想法爲什麼會發生此錯誤?

+0

您在更新1中編寫的代碼不起作用。請參閱我的答案更新,我已經解釋了原因,並提供了替代 –

回答

1

您必須在實體框架之外進行始終加密的相關遷移。這個博客應該幫助 https://blogs.msdn.microsoft.com/sqlsecurity/2015/08/27/using-always-encrypted-with-entity-framework-6/

如果要加密現有列,您可以使用Always Encrypted Wizard in SSMS,或使用這篇文章解釋how to migrate existing data

此外,請注意,通過C#(.NET 4.6.1+客戶端)應用程序進行批量插入是受支持的。

你可以在C#中使用SqlBulkCopy,具體使用SqlBulkCopy.WriteToServer(IDataReader)方法來做到這一點。

  • 使用與您的純文本表(unencryptedTable)相同的模式創建一個新表(encryptedTable),但打開了所需列的加密。
  • 待辦事項SELECT * FROM unencryptedTable加載在一個SqlDataReader數據然後使用SqlBulkCopy的使用SqlBulkCopy.WriteToServer(IDataReader的)方法

例如, 表明文將其加載到encryptedTable

CREATE TABLE [dbo].[Patients](
[PatientId] [int] IDENTITY(1,1), 
[SSN] [char](11) NOT NULL) 

加密表

CREATE TABLE [dbo].[Patients](
[PatientId] [int] IDENTITY(1,1), 
[SSN] [char](11) COLLATE Latin1_General_BIN2 
    ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, 
    ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', 
    COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL) 

至於爲什麼你的方法不起作用, 當你使用總是加密的參數化時,declare語句的右邊(RHS)需要是一個文字。因爲驅動程序將識別文字併爲您加密。所以,下面的就不行,因爲RHS是一個SQL表達式,不能由駕駛員進行加密

DECLARE @floatCol FLOAT = (SELECT TOP 1 FloatCol FROM TestDecrypted) 
UPDATE [dbo].[TestDecrypted] SET FloatCol2 = @floatCol 

更新:
下面的代碼將無法工作,因爲參數化始終加密僅適用於SSMS

foreach (var valuePair in values) 
{ 
    // The error occurs here 
    Sql([email protected]"DECLARE @value FLOAT = {valuePair.Value} 
UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = @value WHERE Id = '{valuePair.Key}'"); 
} 

然而,如果你重寫代碼如下,應該工作

foreach (var valuePair in values) 
{ 
    SqlCommand cmd = _sqlconn.CreateCommand(); 
    cmd.CommandText = @"UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = @FloatVar WHERE Id = '{valuePair.Key}'");"; 

    SqlParameter paramFloat = cmd.CreateParameter(); 
      paramFloat.ParameterName = @"@FloatVar"; 
      paramFloat.DbType = SqlDbType.Float; 
      paramFloat.Direction = ParameterDirection.Input; 
      paramFloat.Value = floatValue; 
      cmd.Parameters.Add(paramFloat); 

    cmd.ExecuteNonQuery(); 


} 

希望有幫助,如果您還有其他問題,請留下評論。

+0

感謝您的答案!嚮導不滿足我的要求,因爲我想在代碼優先遷移中遷移這些數據。 SqlBulkCopy在遷移中也不起作用,因爲新列只有在所有'Up'方法運行後才存在。因此我們不能在這個方法內以這種方式將數據插入到這個列中。 – JoaoRibeiro

+1

您必須在實體框架之外進行始終加密的相關遷移。這個博客應該幫助你.https://blogs.msdn.microsoft.com/sqlsecurity/2015/08/27/using-always-encrypted-with-entity-framework-6/讓我知道你是否面臨任何問題 –

+0

不是我想讀的,但它是我需要的答案:不能僅使用EF遷移對現有列進行加密。然後我會使用SSMS嚮導來完成它。幸運的是,我沒有很多帶有現有數據的數據庫實例。謝謝! – JoaoRibeiro