Colonnes chiffrées avec Entity Framework

c# encryption entity entity-framework mysql

Question

Quelqu'un a trouvé un bon moyen d'extraire des valeurs chiffrées de la base de données via le framework d'entités 4?

J'ai une base de données MySql avec quelques colonnes chiffrées avec des_encrypt et je dois pouvoir obtenir ces valeurs aussi facilement que possible, et bien sûr, les mettre à jour et les insérer.

Je pense que c'est assez étrange, il ne semble pas y avoir de support intégré pour cela dans EF. Même notre propre système ORM construit prend en charge cela. Nous ajoutons simplement un commentaire "crypté" pour chaque champ crypté et l'outil ORM ajoutera des_decrypt (column) et des_encrypt (column) dans les requêtes.

N'importe qui?

Réponse acceptée

IMO, vous devez le chiffrer avant de le placer dans la base de données et le stocker en tant que données binaires. Ensuite, vous pouvez facilement obtenir l' byte[] avec EF.

EDIT: Que se passe-t-il si vous utilisez une procédure stockée pour effectuer toutes les des_encrypt et des_decrypt , ainsi que les selects/inserts/deletes pour vous? Ensuite, EF fera toujours le mappage pour vous?


Réponse populaire

Ceci est un exemple d'implémentation de la réponse proposée par @TheCloudlessSky. Je pensais que cela aiderait tous ceux qui se demandaient comment l’appliquer.

Je travaillais avec une base de données existante, donc la classe de modèle de base a été générée automatiquement pour moi.

User.cs généré automatiquement:

namespace MyApp.Model 
{
    public partial class User
    {
        public int UserId { get; set; }
        public byte[] SSN { get; set; }
        ...
    }
}

J'ai créé mon propre utilisateur.cs. (Notez qu'il se trouve dans le même espace de noms que le fichier User.cs généré automatiquement et qu'il n'y a pas eu d'erreur de compilation, car le fichier User.cs généré automatiquement a été déclaré en tant que classe partielle ! De plus, mon propre fichier User.cs ne peut pas figurer dans le même dossier que le fichier auto. généré User.cs à cause d'un conflit de nom de fichier!)

namespace MyApp.Model 
{
    public partial class User
    {
        public string DecryptedSSN { get; set; }
        ...
    }
}

Maintenant, chaque fois que je récupèrerais User de mon DbContext, je verrai toutes les propriétés définies dans la classe générée automatiquement ainsi que celles définies dans ma classe améliorée.

Voici une implémentation de mon UserRepository.cs:

namespace MyApp.Model
{
    public interface IUserRepository 
    {
        User Get(int userId);
        ...
    }

    public class UserRepository : IUserRepository
    {
        public User GetById(int userId)
        {
            using (var dataContext = MyDbContext())
            {
                var user = dataContext.Users.Find(u => u.UserId == userId);
                var decryptedSSNResult = dataContext.Decrypt(u.SSN);
                user.DecryptedSSN = decryptedSSNResult.FirstOrDefault();
                return user;
            }
        }
    }
}

Maintenant, vous vous demandez peut-être comment et où ai-je obtenu MyDbContext.Decrypt ()?

Ce n'est pas généré automatiquement pour vous. Toutefois, vous pouvez importer cette procédure stockée dans votre fichier Model.Context.cs généré automatiquement. (Ce processus est très bien décrit dans l'article officiel d'EntityFramework: Comment: importer une procédure stockée (Outils de modèle de données d'entité) à l' adresse http://msdn.microsoft.com/en-us/library/vstudio/bb896231(v=vs .100) .aspx )

Juste au cas où vous ne sauriez pas à quoi le résultat final devrait ressembler, voici ce qui a été automatiquement généré dans mon Model.Context.cs:

namespace MyApp.Model
{
    // using statements found here

    public partial class MyDbContext : DbContext
    {
        public MyDbContext()
            : base("name = MyDbContext")
        { }

        public virtual ObjectResult<string> Decrypt(byte[] encryptedData)
        {
            var encryptedDataParameter = encryptedData != null ? 
                            new ObjectParameter("encryptedData", encryptedData) :
                            new ObjectParameter("encryptedData", typeof(byte[]));

            return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<string>("Decrypt", encryptedDataParameter);
        }

        // similar function for Encrypt 
    }
}

Voici à quoi ressemble ma procédure de déchiffrement stockée:

CREATE PROCEDURE decrypt
    @encryptedData VARBINARY(8000)
AS
BEGIN
    OPEN SYMMETRIC KEY xxx_Key DECRYPTION BY CERTIFICATE xxx_Cert;

    SELECT CAST(DECRYPTIONBYKEY(@encryptedData) AS NVARCHAR(MAX)) AS data;

    CLOSE ALL SYMMETRIC KEYS;
END;
GO

Considérations de performance

Maintenant que je vous ai montré une mise en oeuvre de la réponse donnée par @TheCloudlessSky, je voudrais souligner rapidement certains points liés aux performances.

1) Chaque fois que vous récupérez un objet utilisateur, 2 trajets sont effectués dans la base de données au lieu de 1. Premier trajet pour récupérer un objet; deuxième voyage pour déchiffrer le SSN. Cela peut entraîner des problèmes de performances si vous ne faites pas attention.

Recommandation : Ne décryptez PAS automatiquement les champs chiffrés! Dans l'exemple ci-dessus, j'ai déchiffré le numéro de sécurité sociale lors de la récupération de l'objet utilisateur. J'ai fait c'était à des fins de démonstration seulement! Demandez-vous si vous avez vraiment besoin du SSN à chaque fois que l'utilisateur est récupéré. Si possible, choisissez le décryptage paresseux par rapport au décryptage rapide!

2) Bien que je n’aie pas démontré cela, chaque fois que vous créez / mettez à jour un objet utilisateur, deux déclenchements sont également effectués vers la base de données. Premier voyage pour le cryptage du SSN; deuxième voyage pour insérer un objet. Là encore, cela peut entraîner des problèmes de performances si vous ne faites pas attention.

Recommandation : Soyez conscient de cet impact négatif sur les performances, mais ne déléguez pas le cryptage et la sauvegarde du SSN en tant que méthode différente. Gardez le tout en une seule opération, sinon vous pourriez oublier de le sauvegarder. La recommandation pour la création / mise à jour est donc opposée à la récupération: optez pour le cryptage rapide au lieu du cryptage différé!



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow