带有Entity Framework的加密列

c# encryption entity entity-framework mysql

有人想出一个通过实体框架4从db中提取加密值的好方法吗?

我有一个MySql数据库,其中一些列使用des_encrypt加密,并且需要能够尽可能简单地获取这些值,当然还有更新和插入它们。

我觉得很奇怪,在EF中似乎没有建立对此的支持。即使是我们自己构建的ORM系统也支持这一点。我们只为加密的每个字段添加“加密”注释,ORM工具将在查询中添加des_decrypt(列)和des_encrypt(列)。

任何人?

一般承认的答案

IMO你应该将它放入数据库之前进行加密并将其存储为二进制数据。然后,您可以轻松地使用EF获取byte[]

编辑:如果您使用存储过程执行所有des_encryptdes_decrypt以及为您selects/inserts/deletes ,该怎么办?那么EF还会为你做映射吗?


热门答案

这是@TheCloudlessSky提出的答案的实现示例。我认为这将有助于任何想知道如何实施它的人。

我正在使用现有的数据库,因此我自动生成了基本的模型类。

自动生成的User.cs:

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

我创建了自己的User.cs. (注意它与自动生成的User.cs位于相同的命名空间中,并且没有编译器错误,因为自动生成的User.cs被声明为部分类 !而且,我自己的User.cs不能与auto-在同一个文件夹中因文件名冲突而生成User.cs!)

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

现在每当我从我的DbContext中检索User时,我将看到自动生成的类中定义的所有属性以及我的增强类中定义的属性。

这是我的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;
            }
        }
    }
}

现在您可能想知道我是从哪里获得MyDbContext.Decrypt()的?

这不是自动为您生成的。但是,您可以将此存储过程导入到自动生成的Model.Context.cs文件中。 (官方EntityFramework文章:如何:导入存储过程(实体数据模型工具)在http://msdn.microsoft.com/en-us/library/vstudio/bb896231(v=vs )中详细记录了此过程.100).aspx

如果您不知道最终结果应该是什么样的,这里是我在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 
    }
}

这就是我的Decrypt存储过程的样子:

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

性能注意事项

现在我已经向您展示了@TheCloudlessSky给出的答案实现,我想快速强调一些与性能相关的要点。

1)每次检索用户对象时,都会对数据库进行2次旅行,而不是1次。检索对象的第一次旅行;解密SSN的第二次旅行。如果您不小心,这可能会导致性能问题。

建议 :不要自动解密加密字段!在上面显示的示例中,我在检索用户对象时解密了SSN。我这样做只是为了演示目的!问自己每次检索用户是否真的需要SSN。如果可能的话,选择懒惰的解密而不是急切的解密!

2)虽然我没有证明这一点,但每次创建/更新用户对象时,也会有2次访问数据库。加密SSN的第一次旅行;插入物体的第二次旅行。如果您不小心,这可能会导致性能问题。

建议 :注意这种性能影响,但不要将SSN的加密和保存委托为不同的方法。将其全部保存在一个操作中,否则您可能会忘记完全保存它。因此,创建/更新的建议与检索相反:选择对延迟加密的急切加密!




许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因