EntityFramework存储敏感数据

时间:2014-09-04 13:00:57

标签: c# .net entity-framework

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

现在,我有这个设置:

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

3 个答案:

答案 0 :(得分: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);
    }
}

只要您不熟悉应用程序中其他地方的加密属性,它就可以正常运行。

答案 1 :(得分:2)

添加属性UnsecuredString并使用[NotMapped]属性进行装饰。 实现getter和setter以解密和加密SecureString数据。

答案 2 :(得分: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之后,我们回过头去除了我们需要的任何东西。

由于