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
已被加密,对该对象的任何进一步使用都是不正确的。
您可以用一对属性来实现这一点,而不是用一个单独的属性来切换加密,一个始终加密,另一个从不加密。
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之后,我们返回并取消键入任何需要的内容。
感谢