【问题标题】:EF Code First Model with Properties that Hold Encrypted Data具有保存加密数据的属性的 EF Code First 模型
【发布时间】:2017-11-10 02:24:12
【问题描述】:

我正在维护的数据库中的表中有一些加密代码。这是大约 2012 年,所以没有“永远在线”加密。 3 列包含加密数据。

如果我对 EF 域进行反向工程,则为该表创建的模型包含类型为 byte[] 的那些列的属性。这是意料之中的,因为列是varbinary。所以,它看起来像这样:

class Person 
{
  public byte[] FirstName { get; set; } // FirstName
}

是否有一种优雅的方式来进行某种 EF 映射/配置,例如 FirstName 类的类型为 string 并由框架自动解密?我意识到我可以使用sql 来实例化一个 Person 对象,但是最好将此处理卸载到框架中。

我见过两种解决方案之一,人们基本上对每个属性都使用 sql 查询。他们用 Encrypt 属性装饰属性并迭代每个属性的属性。但是对于列表中每个对象的每个属性都有一个 sql 查询 - 这并不完全可以缩放。

以前有人“解决”过这个问题吗?

注意:要检索数据,您首先需要发送类似于以下的 sql 语句:

OPEN SYMMETRIC KEY SomeKey DECRYPTION BY CERTIFICATE SomeCertificate

谢谢

【问题讨论】:

  • 我们创建了解密字段的 SQL 视图并映射到该视图。
  • @SteveGreene 实际上我自己也想到了这个解决方案。感谢您对此进行验证。如果您将其作为答案提交,我会很乐意将其标记为“答案”。它必须是实现这一目标的唯一方法。再次感谢史蒂夫。
  • 你可以把答案写出来。

标签: entity-framework entity-framework-6


【解决方案1】:

在这个答案中,我将列出处理 EF 中的加密列需要做的事情。因此,有问题的列将具有VARBINARY(MAX) 的类型。假设您的表看起来像这样:

CREATE TABLE dbo.Person
(
    SomeId int NOT NULL,
    CreatedByUserId uniqueidentifier NULL,
    CreatedUtcDate datetimeoffset(7) NULL,
    Rowversion timestamp NULL,
    FirstName varbinary(MAX) NULL,
    LastName varbinary(MAX) NULL
)

第 1 步 - 创建一个返回解密列的视图。该视图应该与您的表基本相同,但是对于包含加密数据的列,它应该返回解密的数据。它看起来像这样:

CREATE VIEW [dbo].[v_Person]
AS
SELECT [SomeId]
      ,[CreatedByUserId]
      ,[CreatedUtcDate]
      ,[RowVersion]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([FirstName])) [FirstName]
      ,CONVERT(NVARCHAR(50),DECRYPTBYKEY([LastName])) [LastName]
FROM [dbo].[Person]

第 2 步 - 创建域模型 Person 类,使用 string 作为相关属性类型,而不是 byte[](请注意上面 View 中的 select 语句,我们在其中进行了转换解密后的列到NVARCHAR)。

public class Person 
{
    public int SomeId { get; set; }
    public string FirstName { get; set; } // string, not binary
    public string LastName { get; set; } // string, not binary
    public Guid CreatedByUserId { get; set; } 
    public DateTime CreatedUtcDate { get; set; }      
    public int SomeForeignKeyId { get; set; }
}

第 3 步 - 我们需要为该域类设置映射。 (我在这里提出的解决方案是针对 EF6。我知道 EF Core 还不支持单独的映射文件,因此这需要在 DbContext 的 OnModelCreating 事件中完成)。为您的域对象创建一个映射类,如下所示:

public class PersonMap : EntityTypeConfiguration<Person>
{
    public PersonConfiguration(string schema)
    {
        ToTable("v_Person", schema); // note we map to the View
        HasKey(x => x.SomeId);  

        // ... other properties elided for brevity

        Property(x => x.FirstName)
            .HasColumnName(@"FirstName")
            .HasColumnType("nvarchar")
            .IsOptional()
            .HasMaxLength(50);
        Property(x => x.LastName)
            .HasColumnName(@"LastName")
            .HasColumnType("nvarchar")
            .IsOptional()
            .HasMaxLength(50);

        // Foreign keys
        HasRequired(a => a.LogbookEntry)
            .WithOptional(b => b.Person)
            .WillCascadeOnDelete(false);

        MapToStoredProcedures(p =>
            p.Insert(i => i.HasName("Insert_Person"))
                .Update(u => u.HasName("Update_Person"))
                .Delete(d => d.HasName("Delete_Person")));

    }
}

请注意我们如何映射到视图 v_Person,而不是原始表。
还要注意对MapToStoredProcedures 的调用,我接下来会解释。

第 4 步 - 最后一步是为插入、更新和删除创建一些存储过程。当您调用 SaveChanges 时,这些将由 EF 调用,并且将根据实体拥有的 EntityState 调用相关的存储过程。我不会列出所有 3 个,但 Update 存储过程的示例可能类似于:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Update_Person]
    @SomeId INT,
    @CreatedByUserId UNIQUEIDENTIFIER,
    @CreatedUtcDate DATETIME,
    @RowVersion_Original timestamp,
    @FirstName NVARCHAR(50),
    @LastName NVARCHAR(50) = NULL   
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @CertKey NVARCHAR(7) = 'CertKey';

    UPDATE PersonDetail
        SET             
            FirstName = ENCRYPTBYKEY(KEY_GUID(@CertKey), @FirstName),
            LastName = ENCRYPTBYKEY(KEY_GUID(@CertKey), @LastName)          
    WHERE SomeId = @SomeId

    SELECT SomeId, RowVersion
    FROM PersonDetail
    WHERE SomeId = @SomeId
END

如果您做得更好,请随时发表评论。
干杯

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-10
    • 1970-01-01
    • 2011-12-20
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多