EntityFramework存储敏感数据

本文关键字:敏感数据 存储 EntityFramework | 更新日期: 2023-09-27 18:20:41

假设在您的一个实体上,您有一个属性,当您需要保存到数据库时,它需要加密,但当您在代码中处理它时,您只想将其视为纯文本。

现在,我有这样的设置:

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已被加密,对该对象的任何进一步使用都是不正确的。

EntityFramework存储敏感数据

您可以用一对属性来实现这一点,而不是用一个单独的属性来切换加密,一个始终加密,另一个从不加密。

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);
    }
}

只要您不在应用程序的其他地方破坏加密属性,它就应该能很好地工作。

添加属性UnsecuredString并用[NotMapped]属性装饰它。实现getter和setter来解密和加密SecureString数据。

谢谢你的两个建议,我决定同意。。。。我似乎总是在SO.上发帖后想办法解决问题

我想采用一种不必担心添加NotMapped属性等的方法,尽管我知道这很好。

只需像这样重写SaveChanges方法。

public override int SaveChanges()
{
    int result = base.SaveChanges();
    foreach (DbEntityEntry dbEntityEntry in this.ChangeTracker.Entries())
    {
        DecryptSecureString(dbEntityEntry.Entity);
    }
    return result;
}

所有这些都是在调用SaveChanges之后,我们返回并取消键入任何需要的内容。

感谢