参数化(始终加密)-内部存储过程

时间:2018-11-01 13:55:29

标签: sql-server sql-server-2017 always-encrypted

我有一种情况,我需要在proc内使用用于“始终加密”列的文字(硬编码字符串),因为这样做失败并出现以下错误,

  

操作数类型冲突:varchar与nvarchar(20)不兼容   使用(encryption_type ='DETERMINISTIC',   encryption_algorithm_name ='AEAD_AES_256_CBC_HMAC_SHA_256',   column_encryption_key_name ='CEK_Auto4',   column_encryption_key_database_name ='DBName')

我正在尝试对存储过程中的“始终加密”进行参数化,类似于以下内容

GO
    CREATE PROCEDURE InsertProc  
    @Var1 nVarchar(20)  
    As  
    BEGIN     
        DECLARE @Plaintext nvarchar(20)='testText' 

        INSERT INTO testClass(EncryptedCol1,EncryptedCol2,NonEncryptedCol)
        VALUES (@Plaintext,@Var1,default)
    END

我还启用了参数化功能,还启用了连接的列加密设置。创建过程时仍然出现以下错误,

  

过程sp_describe_parameter_encryption,第1行[批量开始行   4]无法准备陈述。发生错误   执行批处理。错误消息是:内部错误。的元数据   语句中的参数'@ p3467a2cdc3d547a3be48f46dfc7e9580'或   procedure <-我的proc代码在这里->'在由返回的结果集中缺少   sp_describe_parameter_encryption。

注意:如果我手动运行proc内部的脚本,我仍然可以执行并插入。但是创建Proc还是有问题

是否可以帮助修复或提供替代解决方案。

2 个答案:

答案 0 :(得分:1)

始终加密的主要目的是使SQL Server(因此您的DBA)无法解密您的敏感数据。为了达到这个目的,SQL Server 绝对没有访问权限,并且不能加密和解密数据。所有加密和解密均由客户端(您的应用程序,SSMS等)执行。为始终加密启用参数化是SSMS的功能。启用它(并为连接指定Column Encryption Setting = Enabled)后,SSMS将检测脚本中声明的变量,将其转换为参数化查询并执行此转换后的版本。这样,参数值将在客户端上加密,而SQL Server将根本看不到它们的纯文本值。

在您的示例中,@ Plaintext不是在脚本中声明的变量,而是存储过程的局部变量。因此,此代码(值的分配)将在SQL Server的引擎本身中执行,并且由于它无法访问加密密钥,因此根本无法对值进行加密。因此,您也需要将此作为存储过程的输入参数。在这种情况下,尝试给它提供一个默认值并在调用该过程时将其忽略会很诱人,但是默认值是存储在元数据中的东西,并且它是纯格式的(未加密)。有人必须对其加密,而唯一可以做到这一点的是客户端。因此,您需要从客户端传递它,而不是将其设置为默认值,即无法在服务器中使用“硬编码值”。

如果这对您来说是一个主要障碍,则“始终加密”可能不是适合您情况的正确技术。如果您使用带有证书的列级加密,那么您将能够执行所有这些操作。但这破坏了“始终加密”的主要优势-DBA无法访问您的秘密。

答案 1 :(得分:1)

我找到了在过程中使用硬编码字符串的解决方法。

  1. 创建一个具有nVarchar列的表(注意:加密的nvarchar与加密的varchar不兼容,同样,您不能将值从较高的数据长度分配给数据长度较低的加密值(例如,不能将加密的变量/列分配为nVarchar(max)转换为nVarchar(20)的加密列。因此,请选择较小的大小。)
  2. 使用与正在考虑的列相同的加密类型和密钥对列进行加密。
  3. 现在您可以使用表中的值来插入,更新,比较等等。操作。您还可以在合并,isnull等函数中使用。

示例:

使用加密列创建表

CREATE TABLE [dbo].[Encrypted_nVarchar_256](
    [SNo] [smallint] IDENTITY(-32768,1) NOT NULL,
    [EncryptValue] [nvarchar](256) COLLATE Latin1_General_BIN2 
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_key], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL,
        [Value_Description] [nvarchar](256) NULL,
     CONSTRAINT [Pk_Enc_nVar_256] PRIMARY KEY CLUSTERED 
    (
        [SNo] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO

将要在过程中使用的值插入文本到加密列中。

DECLARE @EncryptValue  nvarchar(256) ='';
INSERT INTO Encrypted_nVarchar_256(EncryptValue,[Value_Description]) VALUES(@EncryptValue,'Empty string')
DECLARE @EncryptValue1  nvarchar(256) ='Some string you would like to hard code';
INSERT INTO Encrypted_nVarchar_256(EncryptValue,[Value_Description]) VALUES(@EncryptValue1,'Your description')
--more rows as you need
GO

现在您可以在存储过程中使用

 CREATE PROCEDURE InsertProc  
    @Var1 nVarchar(20)  
    As  
    BEGIN    
        --Passing hard coded ''(Empty string) as insert value
        INSERT INTO testTable(EncryptedCol1,EncryptedCol2,NonEncryptedCol)
        SELECT TOP 1 EncryptValue,@Var1,"some string" FROM Encrypted_nVarchar_256 where Sno=-32768
        --Comparing some hard coded string
        SELECT * from  testTable
        where EncryptedCol1=(SELECT TOP 1 EncryptValue FROM Encrypted_nVarchar_256 
 where Sno=-32768)
         --Using in functions
         SELECT COALESCE(EncryptedCol1,(SELECT TOP 1 EncryptValue FROM Encrypted_nVarchar_256  where Sno=-32768)) as [new col name] from  testable

    END

Voila !!!现在您只需稍作改动就可以做任何事情。