【问题标题】:Can't send a paramaterized stored procedure back to SQL Server 2016 with Always Encrypt. Operand type clash:无法使用 Always Encrypted 将参数化存储过程发送回 SQL Server 2016。操作数类型冲突:
【发布时间】:2019-11-25 19:29:14
【问题描述】:

使用 SQL Server 2016、Visual Studio 2017 和 .Net 4.7.1 框架。我有一个表 (tJobs),其中有一列名为 TRAN_NO。它是一个`nvarchar(11)。我准备了“始终加密”的表格。启用 SQL Server 中的“启用参数化”复选框。更改了 SSMS 连接并添加了“Column Encryption Setting=enabled”。

AE 向导完成后,我看到列现在已在 SSMS 中加密。我导出 AE 的公钥和私钥并将它们复制到我的开发 PC。我打开证书管理器并将这些密钥导入开发 PC。

我在 SSMS 中运行以下命令,它成功更新了 TRAN_NO 列:

Declare @Tran_No nvarchar(11) = 'A124000054A'
Update CCJOB
Set TRAN_NO = @TRAN_NO
Where Job_No = '235877'

SQL 探查器为 TRAN_NO 字段发送加密数据。这是因为我在选项中添加了加密连接字符串变量和参数化。所以在 SSMS 中它按预期工作(见下文)。

sp_executesql N'DECLARE @Tran_No AS NVARCHAR (11) = @p5c6c097b89b449d184469863f8e8685c;

更新 CCJOB SET TRAN_NO = @Tran_No WHERE Job_No = ''235877'';

”,N '@ p5c6c097b89b449d184469863f8e8685c nvarchar的(11)',@ p5c6c097b89b449d184469863f8e8685c = 0x0157D68B171F2B325C21CF0914EEC4D4E7A91EBC90B61531E19413E3F5F514EDE58F827C5E983F56A1612E15BB817A5B65A8284D3FDE121F5B0C3F5BDC25CC68A3EB8AF52E3A0D212E0C41A0DE60B7BE77 P>

到目前为止一切顺利。

我打开使用此表的 .Net 2017 应用程序并设置连接字符串:

Data Source=IC-SQL5;Integrated Security=SSPI;Initial Catalog=IC_CC2; Column Encryption Setting=enabled;

当我运行应用程序时,它成功地从数据库中提取 TRAN_NO 字段,对其进行解密,并将其显示在我的文本框中。惊人的。我喜欢它。

我需要做的最后一件事是在文本框更改时将更改写回数据库。必须通过代码完成。 (旁注:使用数据源绑定控件也不起作用,并在尝试生成更新命令时抛出错误)

我在代码中运行以下更新命令:

Dim sStr As String = "Data Source=IC-SQL5;Integrated Security=SSPI;Initial Catalog=IC_CC2; Column Encryption Setting=enabled"

Dim oCN As New SqlClient.SqlConnection(sStr)

Dim oCom As New SqlClient.SqlCommand("spUpdate_CCJOB2", oCN)
oCom.CommandType = CommandType.StoredProcedure

oCN.Open()

oCom.Parameters.AddWithValue("@JOBNO", "235877")

Dim param3 = oCom.CreateParameter()
param3.ParameterName = "@TRAN_NO"
param3.DbType = SqlDbType.NVarChar = 11
param3.Direction = ParameterDirection.Input
param3.Value = "987654321"
oCom.Parameters.Add(param3)

oCom.ExecuteNonQuery()

这是服务器上的存储过程

ALTER PROCEDURE [dbo].[spUpdate_CCJob2]
    @JobNo VARCHAR(6), 
    @TRAN_NO NVARCHAR(11)
AS
    UPDATE CCJOB
    SET TRAN_NO = @TRAN_NO
    WHERE Job_No = @JobNo;

我收到以下错误:

操作数类型冲突:varchar 与使用 (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'IC_CC2') 加密的 nchar(11) 不兼容

我使用 ADO.NET 提供程序和 SqlClient 提供程序尝试了此代码,并得到了相同的错误消息。似乎不是提供商问题。

我尝试将TRAN_NO 更改为NChar,更改列的大小,以及我能想到的所有其他组合。

当我使用参数化查询通过我的 .Net 应用程序发送存储过程时,即使我正确设置了连接字符串,它也会以纯文本形式发送 Tran_No。文档明确指出提供者在发送到 MSSQL 时应该加密 Tran_No 字段? SQL 分析器清楚地显示 TRAN_NO 未加密(见下文)。

exec sp_describe_parameter_encryption N'EXEC [spUpdate_CCJOB2] @JOBNO=@JOBNO, @TRAN_NO=@TRAN_NO',N'@JOBNO varchar(6),@TRAN_NO varchar(11)' exec spUpdate_CCJOB2 @JOBNO='235877',@TRAN_NO='A124000054A'

为什么提供程序在发送到 SQL Server 之前不加密 TRAN_NO 字段?

【问题讨论】:

  • 看看这个页面:docs.microsoft.com/en-us/sql/relational-databases/security/… 我想它会回答你的一些问题。 TL;DR - 不要使用 .AddWithValue。
  • 感谢您的信息。我在这方面找不到任何有助于我的情况的东西。我确实删除了 AddWithValue 并创建了一个参数。没有更改错误消息。
  • 您是否查看了标题为 Errors due to passing plaintext instead of encrypted values 的部分...因为其中描述的错误似乎正是您面临的问题。
  • 是的,但是,给出的示例是如何不发送查询。我正在使用参数来发送查询。我读到的是,提供者在传递给存储过程之前获取明文值并加密数据。我编辑了我的帖子以显示 SSMS 确实加密了该字段,但 .Net 代码不加密该字段。我确定我错过了一些东西,但看不到它。谢谢

标签: operands always-encrypted


【解决方案1】:

感谢 TechGnome。在敲了几天的头之后,我使用了您引用的文章中的示例。我需要进行更新,因此我将示例从插入更改为更新,它可以发送查询字符串。我不能让它作为存储过程工作?

我更喜欢发送存储过程而不是查询字符串。话虽如此,这个解决方案确实有效:

param3.DbType = SQLDbType.NVarChar = 11

改成

param3.DbType = DbType.String

param3.Size = 11

    Dim sStr As String = System.Configuration.ConfigurationManager.ConnectionStrings("IC_CC.My.MySettings.constrIC_CC").ToString
    Dim oCN As New SqlClient.SqlConnection(sStr)
    oCN.Open()

    Using cmd As SqlClient.SqlCommand = oCN.CreateCommand()
        cmd.CommandText = "Update CCJOB set TRAN_NO = @TRAN_NO WHERE Job_No = @JOBNO"
        Dim param1 = cmd.CreateParameter()
        param1.ParameterName = "@JOBNO"
        param1.DbType = DbType.String
        param1.Direction = ParameterDirection.Input
        param1.Value = "235877"
        param1.Size = 6
        cmd.Parameters.Add(param1)

        Dim param3 = cmd.CreateParameter()
        param3.ParameterName = "@TRAN_NO"
        param3.DbType = DbType.String
        param3.Direction = ParameterDirection.Input
        param3.Value = "A111111111A"
        param3.Size = 11
        cmd.Parameters.Add(param3)
        cmd.ExecuteNonQuery()
    End Using

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多