T-SQL/CLR 确定性加密函数

T-SQL/CLR function for deterministic encryption

我有一个 table 用户代理字符串 table 具有以下结构:

UserAgentStringID INT
UserAgentStringValue VARBINARY(8000)

[UserAgentStringValue] 字段使用对称密钥加密。 table 结构的先前版本是:

UserAgentStringID INT
UserAgentStringValue NVARCHAR(4000)
UserAgentStringHASH BINARY(32)

并且我在 [UserAgentStringHASH] 列上有索引以优化搜索者。

对于新格式,这样的索引不如 ENCRYPTION function uses InitializationVector 有效,以便每次使用相同的输入调用加密函数时生成随机值:

Initialization vectors are used to initialize the block algorithm. It is not intended to be a secret, but must be unique for every call to the encryption function in order to avoid revealing patterns.

所以,我可以在我的加密字段上创建索引,但如果我尝试按加密值搜索,我将无法找到任何内容。

我不想使用 HASH 因为使用散列函数不是安全技术。如果有人拥有我的 table 数据并且 table 拥有全部或大量用户代理,he/she 将能够通过哈希执行连接并显示我的数据。

SQL Server 2016 SP 标准版中,我们有 Always Encrypted 允许对列值使用 Deterministic Encryption - 这意味着相等比较有效并且可以创建索引。

我正在寻找一种通过其他技术优化搜索的方法,或者一种使用 CLR 实现确定性加密的方法?

知道没有变通方法对我来说也很好。我想我会用性能来支付数据保护。

我发布了一个解决方法 - 这不是理想的解决方案,但它是速度和安全性之间的折衷。

详情

  • a 列必须加密(比方说电子邮件地址)
  • 必须实现快速搜索(假设电子邮件用于登录,我们需要尽快找到记录)
  • 我们无法使用 Always Encrypted 确定性加密(由于各种原因)
  • 我们不想将散列函数与 salt 一起使用 - 如果每个用户都有 salt,ze 可能能够使用大型样本数据库读取散列值

安全等级

有多种实现安全层次结构的方法。 MSDN 中的以下架构对其进行了很好的描述。

在我们的环境中,我们使用 Database Mater Key -> Certificate -> Symmetric Key 层次结构。只有 DBA know DMK 密码,才能访问证书和对称密钥。一些开发人员可以处理 encrypt/decrypt 数据(使用纯 T-SQL)而其他人则不能。

请注意,使用 Always Encrypted 可以进行角色分离 - 使用数据的人员无权访问密钥,有权访问密钥的人员无权访问数据。在我们的案例中,我们希望保护我们的数据不受外界影响,并拥有其他技术 granting/logging 内部数据访问。

有权访问加密数据的开发人员

可以访问受保护数据的开发人员可以对其进行加密和解密。他们无权访问对称密钥值。如果可以访问对称密钥值,则 ze 能够 decrypt 没有用于保护对称密钥的证书的数据事件。基本上,只有 sys.admins 和 db_owners 可以访问对称密钥值。

如何哈希

我们需要哈希来进行快速搜索,但我们不能使用未加密的盐。从安全角度来看,没有加盐的哈希就像纯文本。因此,我们决定使用对称密钥值作为盐。是这样的:

SELECT @SymmetricKeyValue = CONVERT(VARCHAR(128), DECRYPTBYCERT(C.[certificate_id], KE.[crypt_property]), 1)
FROM [sys].[symmetric_keys] SK
INNER JOIN [sys].[key_encryptions] KE
    ON SK.[symmetric_key_id] = KE.[key_id] 
INNER JOIN [sys].[certificates] C
    ON KE.[thumbprint] = C.[thumbprint]
WHERE SK.[name] = @SymmetricKeyName;

并将该值连接到您的电子邮件地址,然后计算哈希值。这对我们有好处,因为我们将哈希绑定到安全层次结构。并且它不是每条记录的不同盐,它是相同的 - 但如果知道对称密钥值,则 ze 能够直接解密数据。

注意事项

您需要创建使用 EXECUTE AS OWNER 子句按散列值搜索或计算散列的例程(存储过程、触发器)。否则,开发人员将无法执行它们,因为只有 sys.admins 和 db_owners 可以访问对称密钥值。