Как сначала шифровать данные в коде Entity Framework?

Я пытался и не смог найти хороший подход к шифрованию данных SQL с помощью First Framework Framework Code First. Я должен указать на это тем, что я размещаю в Azure и не имею доступа к собственному SQL-шифрованию.

Принимая страницу SecurEntity, я полностью реализовал подход, который использует SaveChanges и ObjectMaterialized для обработки шифрования/дешифрования объектов, но при тестировании я обнаружили, что это слишком ненадежно для использования.

Вот пример некоторой реализации:

public override int SaveChanges()
{
    var pendingEntities = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager
        .GetObjectStateEntries(EntityState.Added | EntityState.Modified)
        .Where(en => !en.IsRelationship).ToList();

    foreach (var entry in pendingEntities) //Encrypt all pending changes
        EncryptEntity(entry.Entity);

    int result = base.SaveChanges();

    foreach (var entry in pendingEntities) //Decrypt updated entities for continued use
        DecryptEntity(entry.Entity);

    return result;
}

void ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
{
    DecryptEntity(e.Entity);
}

Я видел другие сообщения, которые вручную шифруют/дешифруют через вторичные свойства, например:

public Value { get; set; }

[NotMapped]
public DecryptedValue
{
    get { return Decrypt(this.Value); }
    set { this.Value = Encrypt(value); }
}

Это, безусловно, будет работать, но я считаю, что этот подход... не идеален. При использовании этого подхода все разработчики должны пройти через все зашифрованные свойства, чтобы найти, какие из них они могут использовать.

Наиболее идеальным решением для меня было бы переопределить получение/настройку каждого значения на уровне доступа к данным. Есть ли способ сделать это? Если нет, как я могу реализовать шифрование данных с помощью Entity Framework - Code First, чтобы было легко поддерживать и работать с?

Ответ 1

У меня хорошие новости. Нестабильность, которую я испытывал с помощью метода SaveChanges/ObjectMaterialized, объяснялась тем, что DetectChanges() не вызывается до тех пор, пока DbContext не выполнит сохранение.

Я смог исправить это, позвонив DetectChanges(), прежде чем я вытащил добавленные/измененные записи из ObjectStateManager. Это очистило любые странности состояния объекта, которые вызывают противоречивое поведение шифрования.

Результирующий код:

public override int SaveChanges()
{
    var contextAdapter = ((IObjectContextAdapter)this);

    contextAdapter.ObjectContext.DetectChanges();

    var pendingEntities = contextAdapter.ObjectContext.ObjectStateManager
        .GetObjectStateEntries(EntityState.Added | EntityState.Modified)
        .Where(en => !en.IsRelationship).ToList();

    foreach (var entry in pendingEntities) //Encrypt all pending changes
        EncryptEntity(entry.Entity);

    int result = base.SaveChanges();

    foreach (var entry in pendingEntities) //Decrypt updated entities for continued use
        DecryptEntity(entry.Entity);

    return result;
}

EDIT. Добавлен образец DataContext, чтобы увидеть мое сквозное решение для шифрования всех объектов. Примечание. Вам не нужно использовать настраиваемый атрибут для шифрования свойств. Источник