Skip to content

Beiträge

Implementierung transparenter Verschlüsselung mit NHibernate Listeners (Interceptors)

3. November 2014 • 5 Min. Lesezeit

Implementierung transparenter Verschlüsselung mit NHibernate Listeners (Interceptors)

Mussten Sie schon einmal Daten in der Datenbank verschlüsseln? In diesem Beitrag erkunde ich, wie man nHibernate Listeners verwendet, um Daten zu verschlüsseln und zu entschlüsseln, die von und in Ihre Datenbank gelangen. Die Kryptographie wird für Ihre Anwendung transparent sein.

Warum sollten Sie das tun wollen? SQL Server hat Verschlüsselung in das Produkt eingebaut. Das ist wahr, aber wenn Sie in die Cloud wechseln und SQL Azure verwenden möchten, benötigen Sie eine Art Kryptographie-Strategie. SQL Azure unterstützt keine Datenbankverschlüsselung.

Was ist ein nHibernate Listener? Ich denke an einen Listener als ein Stück Code, das ich in spezifische Erweiterungspunkte im nHibernate-Persistierungs- und Datenhydratations-Lebenszyklus einschleusen kann.

Zum Zeitpunkt dieses Artikels sind die folgenden Erweiterungspunkte in nHibernate verfügbar.

  • IAutoFlushEventListener
  • IDeleteEventListener
  • IDirtyCheckEventListener
  • IEvictEventListener
  • IFlushEntityEventListener
  • IFlushEventListener
  • IInitializeCollectionEventListener
  • ILoadEventListener
  • ILockEventListener
  • IMergeEventListener
  • IPersistEventListener
  • IPostCollectionRecreateEventListener
  • IPostCollectionRemoveEventListener
  • IPostCollectionUpdateEventListener
  • IPostDeleteEventListener
  • IPostInsertEventListener
  • IPostLoadEventListener
  • IPostUpdateEventListener
  • IPreCollectionRecreateEventListener
  • IPreCollectionRemoveEventListener
  • IPreCollectionUpdateEventListener
  • IPreDeleteEventListener
  • IPreInsertEventListener
  • IPreLoadEventListener
  • IPreUpdateEventListener
  • IRefreshEventListener
  • IReplicateEventListener
  • ISaveOrUpdateEventListener

Die Liste ist umfangreich.

Um transparente Kryptographie zu implementieren, müssen wir den richtigen Ort finden, um die Daten zu verschlüsseln und zu entschlüsseln. Für die Verschlüsselung der Daten verwenden wir IPostInsertEventListener und IPostUpdateEventListener. Mit diesen Events fangen wir die neuen Daten und die aktualisierten Daten ab, die in die Datenbank gelangen. Für die Entschlüsselung verwenden wir den IPreLoadEventListener.

Für diese Demonstration verwenden wir die DatabaseCryptography-Klasse für die Verschlüsselung und Entschlüsselung. Die Kryptographie-Implementierung ist für diesen Artikel nicht wichtig.

IPreLoadEventListener

public class PreLoadEventListener : IPreLoadEventListener
{
readonly DatabaseCryptography _crypto = new DatabaseCryptography();

///
/// Called when [pre load].
///

///The event. public void OnPreLoad(PreLoadEvent @event)
{
_crypto.DecryptProperty(@event.Entity, @event.Persister.PropertyNames, @event.State);
}
}

IPreInsertEventListener

public class PreInsertEventListener : IPreInsertEventListener
{
readonly DatabaseCryptography _crypto = new DatabaseCryptography();

///
/// Return true if the operation should be vetoed
///

///The event. /// true if XXXX, false otherwise.
public bool OnPreInsert(PreInsertEvent @event)
{
_crypto.EncryptProperties(@event.Entity, @event.State, @event.Persister.PropertyNames);

return false;
}
}

IPreUpdateEventListener

public class PreUpdateEventListener : IPreUpdateEventListener
{
readonly DatabaseCryptography _crypto = new DatabaseCryptography();

///
/// Return true if the operation should be vetoed
///

///The event. /// true if XXXX, false otherwise.
public bool OnPreUpdate(PreUpdateEvent @event)
{
_crypto.EncryptProperties(@event.Entity, @event.State, @event.Persister.PropertyNames);

return false;
}
}

Es ist wichtig zu beachten, dass sowohl IPreUpdateEventListener als auch IPreInsertEventListener false zurückgeben müssen, andernfalls wird das Insert/Update-Event abgebrochen.

Jetzt, da wir die Listeners implementiert haben, müssen wir sie bei nHibernate registrieren. Ich verwende FluentNHibernate, daher wird dies anders sein, wenn Sie rohes nHibernate verwenden.

SessionFactory

public class SessionFactory
{
///
/// Creates the session factory.
///

/// ISessionFactory.
public static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()

.Database(MsSqlConfiguration.MsSql2012
.ConnectionString(c => c
.FromConnectionStringWithKey("DefaultConnection")))

.Mappings(m => m.FluentMappings.AddFromAssemblyOf())
.ExposeConfiguration(s =>
{
s.SetListener(ListenerType.PreUpdate, new PreUpdateEventListener());
s.SetListener(ListenerType.PreInsert, new PreInsertEventListener());
s.SetListener(ListenerType.PreLoad, new PreLoadEventListener());
})
.BuildConfiguration()
.BuildSessionFactory();
}

Wenn Daten auf Anwendungsebene entschlüsselt und verschlüsselt werden, macht das die Daten in der Datenbank nutzlos. Sie müssen die Daten zurück in die Anwendung bringen, um die Werte der verschlüsselten Felder zu lesen. Wir möchten die Felder begrenzen, die verschlüsselt werden, und wir möchten nur String-Werte verschlüsseln. Die Verschlüsselung von etwas anderem als String-Werten verkompliziert die Dinge. Es gibt nichts, was sagt, dass wir keine Daten verschlüsseln können, aber dies erfordert, dass das Datumsfeld in der Datenbank zu einem String-Feld (nvarchar oder varchar) wird, um die verschlüsselten Daten zu halten. Sobald wir das tun, verlieren wir die Fähigkeit, auf dem Datumsfeld von der Datenbank aus zu operieren.

Um zu identifizieren, welche Felder wir verschlüsselt und entschlüsselt haben möchten, verwende ich Marker-Attribute.

Encrypt Attribute

public class EncryptAttribute : Attribute
{
}

Decrypted Attribute

public class DecryptAttribute : Attribute
{
}

Um das EncryptAttribute und das DecryptedAttribute in Aktion zu sehen, werfen wir einen Blick in die DatabaseCryptography-Klasse.

DatabaseCryptography

public class DatabaseCryptography
{
    private readonly Crypto _crypto = ObjectFactory.GetInstance();

    ///
    /// Encrypts the properties.
    ///
    ///The entity. ///The state. ///The property names. 
    public void EncryptProperties(object entity, object[] state, string[] propertyNames)
    {
        Crypt(entity, propertyNames, s = >
        _crypto.Encrypt(s),
        state)
        ;
    }

    ///
    /// Crypts the specified entity.
    ///

    ///
    ///The entity. ///The state. ///The property names. ///The crypt.
    private void Crypt(object entity, string[] propertyNames, Func<string, string> crypt, object[] state) where T : Attribute
    {
        if (entity != null)
        {
            var properties = entity.GetType().GetProperties();

            foreach (var info in properties)
            {
                var attributes = info.GetCustomAttributes(typeof (T), true);

                if (attributes.Any())
                {
                    var name = info.Name;
                    var count = 0;

                    foreach (var s in propertyNames)
                    {
                        if (string.Equals(s, name, StringComparison.InvariantCultureIgnoreCase))
                        {
                            var val = Convert.ToString(state[count]);
                            if (!string.IsNullOrEmpty(val))
                            {

                                val = crypt(val);
                                state[count] = val;
                            }

                            break;
                        }

                        count++;
                    }
                }
            }
        }
    }

    ///
    /// Decrypts the property.
    ///
    ///The entity. ///The state. ///The property names. 
    public void DecryptProperies(object entity, string[] propertyNames, object[] state)
    {
        Crypt(entity, propertyNames, s = >
        _crypto.Decrypt(s),
        state)
        ;
    }

}

Das war’s. Jetzt wird die Verschlüsselung und Entschlüsselung von Daten für die Anwendung transparent sein und Sie können fröhlich weitermachen und das nächste Facebook entwickeln.

Autor: Chuck Conway ist spezialisiert auf Software-Engineering und Generative KI. Verbinden Sie sich mit ihm in den sozialen Medien: X (@chuckconway) oder besuchen Sie ihn auf YouTube.

↑ Zurück nach oben

Das könnte dir auch gefallen