2014-09-04 225 views
0

對你的一個實體說你有一個屬性,當你需要保存到數據庫時,它需要加密,但是當你在代碼中處理它時,你只需要簡單地對待它文本。存儲敏感數據的EntityFramework

現在,我有這樣的設置:

public class MyEntity 
{ 
    [SecureStringAttribute] 
    public string SecureString {get;set;} 
} 

我的DbContext,這就是 「神奇」 發生。

public MyDbContext() 
    : base("conn") 
{ 
    ((IObjectContextAdapter)this).ObjectContext.SavingChanges += ObjectContextOnSavingChanges; 
    ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += ObjectContextOnObjectMaterialized; 
} 

private void ObjectContextOnObjectMaterialized(object sender, ObjectMaterializedEventArgs e) 
{ 
    DecryptSecureString(e.Entity); 
} 

private void ObjectContextOnSavingChanges(object sender, EventArgs e) 
{ 
    EncryptSecureStrings(sender as ObjectContext); 
} 

private void DecryptSecureString(object entity) 
{ 
    if (entity != null) 
    { 
     foreach (
      PropertyInfo propertyInfo in 
       EntityFrameworkSecureStringAttribute.GetSecureStringProperties(entity.GetType())) 
     { 
      string encryptedValue = propertyInfo.GetValue(entity) as string; 
      if (!string.IsNullOrEmpty(encryptedValue)) 
      { 
       string decryptedValue = EncDec.Decrypt(encryptedValue); 
       propertyInfo.SetValue(entity, decryptedValue); 
      } 
     } 
    } 
} 

private void EncryptSecureStrings(ObjectContext context) 
{ 

    if (context != null) 
    { 
     foreach (ObjectStateEntry objectStateEntry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Where(x => x.Entity != null)) 
     { 

      object[] data = new object[objectStateEntry.CurrentValues.FieldCount]; 
      objectStateEntry.CurrentValues.GetValues(data); 

      PropertyInfo[] properties = 
       EntityFrameworkSecureStringAttribute.GetSecureStringProperties(objectStateEntry.Entity.GetType()); 

      foreach (PropertyInfo propertyInfo in properties) 
      { 
       string currentValue = objectStateEntry.CurrentValues[propertyInfo.Name] as string; 
       if (!string.IsNullOrEmpty(currentValue)) 
       { 
        int index = objectStateEntry.CurrentValues.GetOrdinal(propertyInfo.Name); 
        string newVal = EncDec.Encrypt(currentValue); 
        objectStateEntry.CurrentValues.SetValue(index, newVal); 

       } 
      } 

     } 
    } 
} 

它直截了當我只是在保存和加載時加密/解密字符串。但是,如果我做到以下幾點:

MyEntity entity = new MyEntity(){SecureString= "This is secret!!"}; 
dbContext.SaveChanges(); 

此時entity.SecureString已經加密,並且與此對象的任何進一步的使用將是不正確的。

+1

你有沒有考慮過離開'單獨SecureString'並將其標記爲'protected'再曝使用'SecureString'作爲其後備存儲集中化加密了'DecryptedString'財產的get /解密邏輯/該屬性的集合?屬性/反射解決方案似乎有點過分。 – 2014-09-04 13:16:02

回答

0

謝謝你們兩位的建議,我決定跟這個一起工作......我總是覺得在SO上張貼之後纔會看到數字。

我想去一個方法,我不必擔心添加NotMapped屬性等,雖然我知道這工作正常。

只需重寫像這樣的SaveChanges方法即可。

public override int SaveChanges() 
{ 
    int result = base.SaveChanges(); 

    foreach (DbEntityEntry dbEntityEntry in this.ChangeTracker.Entries()) 
    { 
     DecryptSecureString(dbEntityEntry.Entity); 
    } 
    return result; 
} 

這一切確實是調用SaveChanges之後,我們回去通過和decyryped點兒,我們需要。

感謝

+0

我不會觸及'SaveChanges'代碼。嘗試使用上下文中的「SavedChanges」事件以與您在「SavingChanges」中執行的操作對稱的方式進行演奏。數據保存到數據庫後發生此事件。 – Andrew 2014-09-04 14:52:20

3

而不是一個單一的屬性,將被翻轉/加密,你可以做一對屬性 - 一個永遠是加密的,而一個永遠不會加密。

public class MyModel 
{ 
    public string EncryptedInfo { get; set; } 
    public string PlainTextInfo { 
     get 
     { 
      return Decrypt(EncryptedInfo); 
     } 
     set 
     { 
      EncryptedInfo = Encrypt(value); 
     } 
} 

和模型構建,忽視了加密屬性:

public class MyDbContext : DbContext 
{ 
    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<MyModel>() 
      .Ignore(m => m.PlainTextInfo); 
    } 
} 

只要你不與你的應用程序的其他地方加密財產混亂,它應該很好地工作。

+0

感謝您的建議 – 2014-09-04 14:02:47

2

添加屬性UnsecuredString並用[NotMapped]屬性裝飾它。 實現getter和setter來解密和加密SecureString數據。

+0

感謝您的建議 – 2014-09-04 14:10:32