Skip to content

Articles

Implémentation du chiffrement transparent avec les écouteurs NHibernate (Intercepteurs)

3 novembre 2014 • 5 min de lecture

Implémentation du chiffrement transparent avec les écouteurs NHibernate (Intercepteurs)

Avez-vous déjà dû chiffrer des données dans la base de données ? Dans cet article, j’explore comment utiliser les écouteurs nHibernate pour chiffrer et déchiffrer les données provenant de votre base de données et y allant. La cryptographie sera transparente pour votre application.

Pourquoi voudriez-vous faire cela ? SQL Server dispose du chiffrement intégré au produit. C’est vrai, mais si vous migrez vers le cloud et souhaitez utiliser SQL Azure, vous aurez besoin d’une stratégie de cryptographie. SQL Azure ne supporte pas le chiffrement de base de données.

Qu’est-ce qu’un écouteur nHibernate ? Je considère un écouteur comme un morceau de code que je peux injecter dans des points d’extensibilité spécifiques du cycle de vie de persistance et d’hydratation des données de nHibernate.

À la date de rédaction, les points d’extensibilité suivants sont disponibles dans nHibernate.

  • 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

La liste est extensive.

Pour implémenter la cryptographie transparente, nous devons trouver le bon endroit pour chiffrer et déchiffrer les données. Pour chiffrer les données, nous utiliserons IPostInsertEventListener et IPostUpdateEventListener. Avec ces événements, nous capturerons les nouvelles données et les données mises à jour allant dans la base de données. Pour déchiffrer, nous utiliserons IPreLoadEventListener.

Pour cette démonstration, nous utiliserons la classe DatabaseCryptography pour chiffrer et déchiffrer. L’implémentation de la cryptographie n’est pas importante pour cet article.

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;
}
}

Il est important de noter que IPreUpdateEventListener et IPreInsertEventListener doivent tous deux retourner false, sinon l’événement d’insertion/mise à jour sera annulé.

Maintenant que nous avons implémenté les écouteurs, nous devons les enregistrer auprès de nHibernate. J’utilise FluentNHibernate, donc ce sera différent si vous utilisez nHibernate brut.

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();
}

Lorsque vous déchiffrez et chiffrez des données au niveau de l’application, cela rend les données inutiles dans la base de données. Vous devrez ramener les données dans l’application pour lire les valeurs des champs chiffrés. Nous voulons limiter les champs qui sont chiffrés et nous voulons seulement chiffrer les valeurs de chaîne. Chiffrer autre chose que les valeurs de chaîne complique les choses. Rien ne dit que nous ne pouvons pas chiffrer les dates, mais le faire nécessitera que le champ de date dans la base de données devienne un champ string (nvarchar ou varchar), pour contenir les données chiffrées, une fois que nous le ferons, nous perdons la capacité d’opérer sur le champ de date à partir de la base de données.

Pour identifier les champs que nous voulons chiffrer et déchiffrer, j’utiliserai des attributs marqueurs.

Encrypt Attribute

public class EncryptAttribute : Attribute
{
}

Decrypted Attribute

public class DecryptAttribute : Attribute
{
}

Pour voir EncryptAttribute et DecryptedAttribute en action, nous jetterons un coup d’œil à la classe DatabaseCryptography.

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)
        ;
    }

}

C’est tout. Maintenant, le chiffrement et le déchiffrement des données seront transparents pour l’application et vous pourrez continuer votre chemin en construisant le prochain Facebook.

Auteur : Chuck Conway est un ingénieur IA avec près de 30 ans d’expérience en génie logiciel. Il construit des systèmes IA pratiques — pipelines de contenu, agents d’infrastructure et outils qui résolvent des problèmes réels — et partage ce qu’il apprend en chemin. Connectez-vous avec lui sur les réseaux sociaux : X (@chuckconway) ou visitez-le sur YouTube et sur SubStack.

↑ Retour en haut

Vous aimerez peut-être aussi