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 jemals Daten in der Datenbank verschlüsseln? In diesem Beitrag werde ich untersuchen, wie man nHibernate Listeners verwendet, um Daten zu verschlüsseln und zu entschlüsseln, die aus Ihrer Datenbank kommen und in diese gehen. Die Kryptografie wird für Ihre Anwendung transparent sein.

Warum würde man das tun wollen? SQL Server hat Verschlüsselung in das Produkt integriert. Das ist wahr, aber wenn Sie in die Cloud wechseln und SQL Azure verwenden möchten, benötigen Sie eine Art Kryptografiestrategie. SQL Azure unterstützt keine Datenbankverschlüsselung.

Was ist ein nHibernate Listener? Ich stelle mir einen Listener als ein Stück Code vor, das ich in bestimmte Erweiterungspunkte im nHibernate-Persistierungs- und Datenhydratisierungs-Lebenszyklus einfügen kann.

Zum Zeitpunkt des Schreibens 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 Kryptografie zu implementieren, müssen wir den richtigen Ort finden, um die Daten zu verschlüsseln und zu entschlüsseln. Zum Verschlüsseln der Daten verwenden wir IPostInsertEventListener und IPostUpdateEventListener. Mit diesen Ereignissen erfassen wir die neuen Daten und die aktualisierten Daten, die in die Datenbank gehen. Zum Entschlüsseln verwenden wir IPreLoadEventListener.

Für diese Demonstration verwenden wir die DatabaseCryptography-Klasse zum Verschlüsseln und Entschlüsseln. Die Kryptografie-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, sonst wird das Insert/Update-Ereignis abgebrochen.

Jetzt, da wir die Listener 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 Sie Daten auf Anwendungsebene entschlüsseln und verschlüsseln, werden 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, die verschlüsselt werden, begrenzen und nur Zeichenfolgenwerte verschlüsseln. Das Verschlüsseln von anderen Werten als Zeichenfolgenwerten erschwert die Dinge. Es gibt nichts, das uns daran hindert, Daten zu verschlüsseln, aber dies erfordert, dass das Datumsfeld in der Datenbank zu einem String-Feld (nvarchar oder varchar) wird, um die verschlüsselten Daten zu speichern. Sobald wir dies tun, verlieren wir die Möglichkeit, mit dem Datumsfeld aus der Datenbank zu arbeiten.

Um zu identifizieren, welche Felder wir verschlüsseln und entschlüsseln 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 ist alles. Jetzt wird die Verschlüsselung und Entschlüsselung von Daten für die Anwendung transparent sein und Sie können sich auf den Weg machen, um das nächste Facebook zu bauen.

Autor: Chuck Conway ist ein KI-Ingenieur mit fast 30 Jahren Erfahrung in der Softwareentwicklung. Er entwickelt praktische KI-Systeme – Content-Pipelines, Infrastruktur-Agenten und Tools, die echte Probleme lösen – und teilt seine Erkenntnisse unterwegs. Verbinden Sie sich mit ihm in den sozialen Medien: X (@chuckconway) oder besuchen Sie ihn auf YouTube und auf SubStack.

↑ Nach oben

Das könnte dir auch gefallen