2010-07-21 72 views
8

有人想通過實體框架4從數據庫中提取加密值的好方法?使用實體框架加密的列

我得到了一個MySql數據庫,其中有一些使用des_encrypt加密的列,並且需要能夠儘可能簡單地獲取這些值,當然,還需要更新並插入它們。

我認爲這很奇怪,似乎沒有在EF中爲此構建的支持。即使我們自己構建的ORM系統也支持這一點。我們只是爲加密的每個字段添加一個「加密」註釋,並且ORM工具將在查詢中添加des_decrypt(column)和des_encrypt(column)。

有人嗎?

回答

2

國際海事組織你應該加密之前把它放入數據庫並將其存儲爲二進制數據。然後你可以很容易地用EF獲得byte[]

編輯:如果您使用存儲過程爲您執行所有des_encryptdes_decrypt以及selects/inserts/deletes怎麼辦。那麼EF仍然會爲你做映射嗎?

+0

看起來像一個很好的解決方案,如果我創建了一個新的數據庫,我可能會這樣做。 問題是,數據庫非常大,被大量的項目所使用,因此查看代碼並改變它將是一項巨大的工作。 – Andreas 2010-07-22 06:53:10

+0

@Andreas - 查看我上面的修改。 – TheCloudlessSky 2010-07-22 12:02:59

+0

感謝您的建議。 這看起來像一個非常好的主意,我試了一下。 不幸的是,如果我希望能夠對錶中的所有解密數據執行LINQ查詢,則必須先執行存儲過程。這是永久的,因爲它是250,000行,每行5列需要解密。 這樣做:context.AllMembers()。其中​​(x => x.MemberId == 1)將花費太長時間。 當然我可以做一個採用memberid參數的SP,但是如果我想在例如與LINQ的名字? 也許我錯過了一些重要的東西在這裏... – Andreas 2010-07-23 08:46:29

1

您可以使用AES加密(2路加密)。當您需要查詢數據庫時,您可以發送可以表示目標值的加密字符串。

您可以創建一個擴展來解密該實體。

MyTableEntitiesSet.Where(c=>c.MyField == MySeekValue.Encrypt()).First().Decrypt(); 

這可以做一個數據庫查詢。

要注意數據的大小,加密的數據是大...

+4

舊的問題和答案,但請注意,如果您嘗試這樣做,它將只會在您使用固定的初始向量時才起作用,因爲它不會推薦潛在地允許攻擊者瞭解數據。應該使用每個加密的隨機IV,這意味着每次加密某個東西時都會得到不同的值。 – 2013-04-19 16:34:02

-3

在我的特定情況下,我需要加密的信用卡號碼,這始終是16個字符;所以我只是在get(如果lenght!= 16然後解密)和set(如果長度爲16,然後加密)屬性中添加了一個條件。它的工作,並避免了我很多工作。

12

這是@TheCloudlessSky提出的答案的實現示例。我認爲這會幫助那些想知道如何去實施它的人。

我正在使用現有的數據庫,所以基本模型類是爲我自動生成的。

自動生成User.cs:

namespace MyApp.Model 
{ 
    public partial class User 
    { 
     public int UserId { get; set; } 
     public byte[] SSN { get; set; } 
     ... 
    } 
} 

我創建了自己User.cs. (注意它與自動生成的User.cs位於同一個命名空間中,並且沒有編譯器錯誤,因爲自動生成的User.cs被聲明爲部分類!另外,我自己的User.cs不能與自動生成User.cs因爲文件名衝突!)

namespace MyApp.Model 
{ 
    public partial class User 
    { 
     public string DecryptedSSN { get; set; } 
     ... 
    } 
} 

現在,每當我是從我的DbContext檢索用戶,我會看到自動生成的類以及在中定義的定義的所有屬性我的增強類。

這是我的UserRepository的實現。CS:

namespace MyApp.Model 
{ 
    public interface IUserRepository 
    { 
     User Get(int userId); 
     ... 
    } 

    public class UserRepository : IUserRepository 
    { 
     public User GetById(int userId) 
     { 
      using (var dataContext = MyDbContext()) 
      { 
       var user = dataContext.Users.Find(u => u.UserId == userId); 
       var decryptedSSNResult = dataContext.Decrypt(u.SSN); 
       user.DecryptedSSN = decryptedSSNResult.FirstOrDefault(); 
       return user; 
      } 
     } 
    } 
} 

現在你可能想知道如何/在哪裏我MyDbContext.Decrypt()從獲得?

這不是自動生成的。但是,您可以將此存儲過程導入到自動生成的Model.Context.cs文件中。 (這個過程在官方的EntityFramework文章中有很好的記錄:如何導入一個存儲過程(實體數據模型工具)http://msdn.microsoft.com/en-us/library/vstudio/bb896231(v=vs.100).aspx

爲防萬一你不知道結果應該是什麼樣子,是什麼在我的Model.Context.cs自動生成:

namespace MyApp.Model 
{ 
    // using statements found here 

    public partial class MyDbContext : DbContext 
    { 
     public MyDbContext() 
      : base("name = MyDbContext") 
     { } 

     public virtual ObjectResult<string> Decrypt(byte[] encryptedData) 
     { 
      var encryptedDataParameter = encryptedData != null ? 
          new ObjectParameter("encryptedData", encryptedData) : 
          new ObjectParameter("encryptedData", typeof(byte[])); 

      return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<string>("Decrypt", encryptedDataParameter); 
     } 

     // similar function for Encrypt 
    } 
} 

這是我的解密存儲過程的樣子:

CREATE PROCEDURE decrypt 
    @encryptedData VARBINARY(8000) 
AS 
BEGIN 
    OPEN SYMMETRIC KEY xxx_Key DECRYPTION BY CERTIFICATE xxx_Cert; 

    SELECT CAST(DECRYPTIONBYKEY(@encryptedData) AS NVARCHAR(MAX)) AS data; 

    CLOSE ALL SYMMETRIC KEYS; 
END; 
GO 

性能注意事項

既然我已經向您展示了@TheCloudlessSky給出的答案的實現,我想快速地突出顯示一些與性能相關的要點。

1)每次檢索一個用戶對象時,都會有2次到達數據庫而不是1次。第一次檢索對象;第二次解密SSN。如果您不小心,這可能會導致性能問題。

推薦:不要自動解密加密字段!在我上面顯示的例子中,當我檢索用戶對象時,我解密了SSN。我這樣做只是爲了演示目的!問問你自己是否真的需要SSN每次檢索用戶。如果可能的話,選擇通過渴望解密的延遲解密!

2)雖然我沒有證明這一點,但是每次創建/更新用戶對象時,還會有2次到數據庫的行程。第一次加密SSN;第二次插入對象。如果您不小心,這又會導致性能問題。

建議:請注意這種性能下降,但不要委派加密和保存SSN作爲不同的方法。把它全部保存在一個操作中,否則你可能忘記完全保存它。因此,創建/更新的建議與檢索相反:選擇通過懶加密的急切加密!

+0

我給你一個努力票。但我不同意你的方法。我不希望我的數據庫解密值。我可以將所有這些信息存儲在我的應用程序中,而不必兩次前往數據庫。 – mac10688 2015-03-27 13:26:01

+0

@ mac10688我同意你關於多次訪問數據庫的性能問題。通常,爲CUD操作編寫專用存儲過程並通過實體框架將它們鏈接到模型比存儲過程(如加密/解密)更有效。但我想演示一種使用由數據庫而不是應用程序管理的密鑰來實現加密/解密的方法。 – 2015-03-31 03:38:49

+0

如果有人對如何實現這一點感到好奇,我提供了一個鏈接,指向實體框架如何將CUD存儲過程連接到CUD操作:https://msdn.microsoft.com/en-us/data/jj593489。我知道鏈接通常是不受歡迎的,但是由於這個鏈接是MSDN實體框架文檔站點,所以我希望人們不會介意。 – 2015-03-31 03:44:28

1

你可以去DIY /卷 - 自己的加密安全,但每個安全專家會告訴你never, ever, do that。數據安全和加密中最難的部分實際上不是「AES」或某種算法。這是關鍵管理。遲早,你會面對這個野獸,它的方式更難

幸運的是,有一個名爲Crypteron CipherDb的工具可以解決這個問題。事實上,它超越了實體框架加密,還提供了自動防篡改保護,安全密鑰存儲,安全密鑰分配,密鑰延伸,密鑰緩存,訪問控制列表等等。有一個免費社區版,它只需要幾分鐘時間添加到您的應用程序。

當與實體框架集成,你只是註釋數據模型[Secure]或名稱的屬性,以類似Secure_SocialSecurityNumber(該Secure_是關鍵部分)和CipherDb負責剩下的照顧。

例如,你的數據模型是:

public class Patient 
{ 
    public int Id {get; set;} 

    [Secure] 
    public string FullName {get; set;} 

    [Secure] 
    public string SocialSecurityNumber {get; set;} 
} 

而且你的web.config將

<configuration> 
    <configSections> 
    <section 
     name="crypteronConfig" 
     type="Crypteron.CrypteronConfig, CipherCore, Version=2017, Culture=neutral, PublicKeyToken=e0287981ec67bb47" 
     requirePermission="false" /> 
    </configSections> 

    <crypteronConfig> 
    <myCrypteronAccount appSecret="Get_this_from_http://my.crypteron.com" /> 
    </crypteronConfig> 
</configuration> 

它的建議,以確保你的web.config,或者將Crypteron API密鑰(AppSecret )以編程方式(documentation

您可以在GitHub上找到示例應用程序https://github.com/crypteron/crypteron-sample-apps。 。

順便說一下,免費版可以從商業產品中受益,因此除了上述之外,您還可以在一個地方保護流,文件,對象,消息隊列,NoSQL數據庫等。

免責聲明:我在那裏工作,我們有一個免費的社區版,任何人都可以使用(而且我們不賺任何錢)。如果你認爲這很酷,告訴我們,告訴你的朋友。如果您有預算,請獲得商業許可。它可以幫助我們向所有人提供免費版:)