1

我需要将一些信息存储在加密的数据库中(不是散列,我在这里不是在谈论密码),但仍然能够在内存中读取该信息以验证某些场景(因此是加密,而不是散列)。

我想要一种简洁的方法来确定哪些列应该在数据库中加密存储,因为它们将来可能会改变。话虽如此,我想知道以下方法是否可以与 MVC5 和实体框架 6 中的 IdentityProvider 提供的 ApplicationDbContext 一起使用。有什么需要注意的警告吗?或者这甚至是一个很好的想法?如果没有,任何指导将不胜感激。

  • 为了定义列(代码优先),我创建了一个名为“StoreSecurelyAttribute”的属性,该属性可以应用于 Code-First 模型中的不同属性。
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class StoreSecurelyAttribute : Attribute { }
  • 然后,我可以将此属性应用于需要安全存储的任何列(目前仅支持字符串)。
public class UserProfileInfo
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Required, StoreSecurely]
    public string SomePersonalInformation { get; set; }
}
  • 然后在我的 ApplicationDbContext 构造函数中添加以下内容:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext() : base("DefaultConnection", false)
    {
        var ctx = ((IObjectContextAdapter) this).ObjectContext;
        ctx.ObjectMaterialized += OnObjectMaterialized;
        ctx.SavingChanges += OnSavingChanges;
    }

    void OnSavingChanges(object sender, EventArgs e)
    {
        foreach (var entry in ((ObjectContext) sender).ObjectStateManager.GetObjectStateEntries(EntityState.Added |
                                                                                  EntityState.Modified))
        {
            foreach (var propInfo in entry.Entity.GetType().GetProperties()
                .Where(prop => prop.PropertyType == typeof(string) && Attribute.IsDefined(prop, typeof(StoreSecurelyAttribute))))
            {
                var plainTextValue = propInfo.GetValue(entry.Entity) as string;
                // TODO: encrypt using injected encryption provider
                var encryptedValue = Encrypt(plainTextValue); 
                propInfo.SetValue(entry.Entity, encryptedValue);
            }
        }
    }

    void OnObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
    {
        foreach (var propInfo in e.Entity.GetType().GetProperties()
                .Where(prop => prop.PropertyType == typeof(string) && Attribute.IsDefined(prop, typeof(StoreSecurelyAttribute))))
            {
                var encryptedValue = propInfo.GetValue(e.Entity) as string;
                // TODO: decrypt using injected encryption provider
                var plainTextValue = Decrypt(encryptedValue);
                propInfo.SetValue(e.Entity, plainTextValue);
            }
    }
    public override int SaveChanges()
    {
        // Hold onto them before their state changes and they're no longer "added" or "modified"
        var entries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified).ToList();

        // Go Ahead and save...
        var result = base.SaveChanges();

        // After saving to db, we want our local hydrated object to be "correct" so... decrypt...
        foreach (var entry in entries)
        {
            foreach (var propInfo in entry.Entity.GetType().GetProperties()
                .Where(prop => prop.PropertyType == typeof(string) && Attribute.IsDefined(prop, typeof(StoreSecurelyAttribute))))
            {
                var encryptedValue = propInfo.GetValue(entry.Entity) as string;
                var plainTextValue = Decrypt(encryptedValue);
                propInfo.SetValue(entry.Entity, plainTextValue);
            }
        }

        return result;
    }
// ... snip ...
}

更新:我知道这是很多反思,可能会很慢——但我们不会对加密和解密字段过于疯狂,我们加密的字段不会“在每个请求上”都被命中。

4

1 回答 1

0

我会慎重地对受保护数据进行读/写操作。

另外,我不知道您是否需要从写入数据的同一位置读取数据,但如果不需要,请考虑使用非对称加密来保护数据。这样,写入数据的地方(例如 Web 应用程序)只需要访问私钥,而系统中读取数据的其他地方则只需要访问公钥。

于 2014-04-05T22:30:12.470 回答