You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server存储过程解密加密列返回NULL问题解决

问题描述

在SQL Server 2016环境中,已创建对称密钥SymKey_Test,并通过证书Certificate_Test加密ClientContactTest表的PhoneNo列(加密后存储为PhoneNo_Encrypt)。直接执行SQL语句可正常解密该列,但将相同代码封装到存储过程ClientContactTest_LoadRecord_Encrypted后,解密后的PhoneNo列返回NULL。

已完成的配置:

  • 存储过程已授予CRMObjects角色执行权限
  • 尝试为CRMObjects角色授予证书和对称密钥的CONTROL、VIEW DEFINITION权限,但问题未解决

直接执行的SQL代码

OPEN SYMMETRIC KEY SymKey_Test DECRYPTION BY CERTIFICATE Certificate_Test;

SELECT        
    ClientContactTest.ClientID, ClientContactTest.ContactID, 
    ClientContactTest.Title, ClientContactTest.Forename, 
    ClientContactTest.Surname, 
    CONVERT(varchar, DecryptByKey(ClientContactTest.PhoneNo_Encrypt)) AS PhoneNo,  
    ClientContactTest.MobileNo, ClientContactTest.EMailAddress, 
    Lookup_ContactType.Description AS ContactTypeDescription
FROM
    ClientContactTest 
LEFT OUTER JOIN
    Lookup_ContactType ON ClientContactTest.ContactTypeID = Lookup_ContactType.ContactTypeID
WHERE
    (ClientContactTest.ClientID = 7) 
    AND (ClientContactTest.SiteID = 0) 
    AND (ClientContactTest.ContactID = 1)

CLOSE SYMMETRIC KEY SymKey_Test

存储过程代码

CREATE PROCEDURE [dbo].[ClientContactTest_LoadRecord_Encrypted]
AS
BEGIN
    OPEN SYMMETRIC KEY SymKey_Test DECRYPTION BY CERTIFICATE Certificate_Test;

    SELECT        
        ClientContactTest.ClientID, ClientContactTest.ContactID, 
        ClientContactTest.Title, ClientContactTest.Forename, 
        ClientContactTest.Surname, 
        CONVERT(varchar, DecryptByKey(ClientContactTest.PhoneNo_Encrypt)) AS PhoneNo, 
        ClientContactTest.MobileNo, ClientContactTest.EMailAddress, 
        Lookup_ContactType.Description AS ContactTypeDescription
    FROM
        ClientContactTest 
    LEFT OUTER JOIN
        Lookup_ContactType ON ClientContactTest.ContactTypeID = Lookup_ContactType.ContactTypeID
    WHERE
        (ClientContactTest.ClientID = 7) 
        AND (ClientContactTest.SiteID = 0) 
        AND (ClientContactTest.ContactID = 1)

    CLOSE SYMMETRIC KEY SymKey_Test
END

已尝试的权限配置

GRANT CONTROL ON CERTIFICATE :: Certificate_Test TO CRMObjects;
GRANT CONTROL ON SYMMETRIC KEY :: SymKey_Test TO CRMObjects

GRANT VIEW DEFINITION ON SYMMETRIC KEY::SymKey_Test TO CRMObjects
GRANT VIEW DEFINITION ON Certificate::[Certificate_Test] TO CRMObjects
解决方案

1. 补充必要权限

存储过程执行时,CRMObjects角色需要具备证书的REFERENCES权限,以及对称密钥的REFERENCES权限(仅CONTROL和VIEW DEFINITION不足以支持解密操作)。执行以下权限授予语句:

-- 授予证书的REFERENCES权限
GRANT REFERENCES ON CERTIFICATE::Certificate_Test TO CRMObjects;
-- 授予对称密钥的REFERENCES权限
GRANT REFERENCES ON SYMMETRIC KEY::SymKey_Test TO CRMObjects;

2. 配置存储过程执行上下文(可选但推荐)

如果证书和对称密钥的所有者是dbo,而存储过程也是dbo所有,可以通过EXECUTE AS OWNER让存储过程以所有者身份执行,继承所有者的权限,避免权限上下文问题。修改存储过程:

ALTER PROCEDURE [dbo].[ClientContactTest_LoadRecord_Encrypted]
WITH EXECUTE AS OWNER
AS
BEGIN
    OPEN SYMMETRIC KEY SymKey_Test DECRYPTION BY CERTIFICATE Certificate_Test;

    SELECT        
        ClientContactTest.ClientID, ClientContactTest.ContactID, 
        ClientContactTest.Title, ClientContactTest.Forename, 
        ClientContactTest.Surname, 
        CONVERT(varchar, DecryptByKey(ClientContactTest.PhoneNo_Encrypt)) AS PhoneNo, 
        ClientContactTest.MobileNo, ClientContactTest.EMailAddress, 
        Lookup_ContactType.Description AS ContactTypeDescription
    FROM
        ClientContactTest 
    LEFT OUTER JOIN
        Lookup_ContactType ON ClientContactTest.ContactTypeID = Lookup_ContactType.ContactTypeID
    WHERE
        (ClientContactTest.ClientID = 7) 
        AND (ClientContactTest.SiteID = 0) 
        AND (ClientContactTest.ContactID = 1)

    CLOSE SYMMETRIC KEY SymKey_Test
END

3. 验证权限生效

执行以下SQL检查CRMObjects角色的权限是否正确配置:

SELECT 
    dp.name AS principal_name,
    perm.class_desc AS securable_type,
    COALESCE(sec.name, sk.name) AS securable_name,
    perm.permission_name
FROM sys.database_permissions perm
JOIN sys.database_principals dp ON perm.grantee_principal_id = dp.principal_id
LEFT JOIN sys.certificates sec ON perm.class = 1 AND perm.major_id = sec.certificate_id
LEFT JOIN sys.symmetric_keys sk ON perm.class = 2 AND perm.major_id = sk.symmetric_key_id
WHERE dp.name = 'CRMObjects'
AND perm.class_desc IN ('CERTIFICATE', 'SYMMETRIC_KEY');

内容的提问来源于stack exchange,提问作者AztecDeveloper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:19:56