2014-09-04 117 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