【问题标题】:varchar is incompatible with varchar(50) encrypted with (encryption_type = 'DETERMINISTIC'varchar 与用 (encryption_type = 'DETERMINISTIC' 加密的 varchar(50) 不兼容
【发布时间】:2019-08-31 19:06:41
【问题描述】:

我正在尝试从我的应用程序中传递一个参数以在存储过程中进行搜索。我这样传入参数:

SqlParameter param1 = new SqlParameter(@"@FilterCustomerPO", "G06756");
param1.DbType = DbType.AnsiString;
param1.Direction = ParameterDirection.Input;
param1.Size = 50;

sqlCmd.Parameters.Add(param1);

在存储过程中是这样定义的:

ALTER PROCEDURE [dbo].[usp_POListing]
    @FilterCustomerPO VARCHAR (50)
AS
BEGIN
    SELECT * 
    FROM [Order]
    WHERE PONumber = @FilterCustomerPO
END

PONumber 列使用DETERMINISTIC 加密类型加密。

当我传入一个值时,我得到一个错误:

操作数类型冲突:varchar 与使用 (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'ColumnEncryptionKey', column_encryption_key_database_name = 'DataPortal') 加密的 varchar(50) 不兼容>

我看到很多其他人对此进行了报告,但这些解决方案都不适合我。如您所见,我正在使用参数化查询,因此不确定我可能会丢失什么。

编辑:

我也尝试过以这种方式传递参数 - 同样的错误:

sqlCmd.Parameters.Add("FilterCustomerPO", SqlDbType.VarChar, 50);
sqlCmd.Parameters["FilterCustomerPO"].Value = "G06756"

订单表的定义如下:

CREATE TABLE [dbo].[Order]
(
    [OrderID] [INT] IDENTITY(1,1) NOT NULL,
    [CustomerID] [INT] NOT NULL,
    [OrderNumber] [INT] NOT NULL,
    [DBCOrderNumber] [VARCHAR](25) NOT NULL,
    [PONumber] [VARCHAR](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [ColumnEncryptionKey], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL,
    [BillingName] [VARCHAR](255) NOT NULL,

    CONSTRAINT [PK_Order] 
        PRIMARY KEY CLUSTERED ([OrderID] ASC)
                    WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

我的客户端连接字符串还包括Column Encryption Setting=Enabled

请注意:我能够很好地检索数据。当我将参数发送到查询中,并在收到错误时尝试进行比较/过滤。

【问题讨论】:

标签: sql sql-server azure azure-sql-database always-encrypted


【解决方案1】:

这是AlwaysEncrypted,它只使用客户端加密密钥。它旨在防止 SQL Server(或其管理员)能够解密数据。如果您想要使用服务器管理的密钥进行列加密,SQL Server 也有,但它是一个不同的功能。见Encrypt a Column of Data

在 Order.PONumber 的 AlwaysEncrypted 数据类型中,不只是 varchar(50)。这是

[varchar](50) COLLATE Latin1_General_BIN2 
    ENCRYPTED WITH (
      COLUMN_ENCRYPTION_KEY = [ColumnEncryptionKey], 
      ENCRYPTION_TYPE = Deterministic, 
      ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256')

这是列类型的全部部分,因此您不能使用varchar(50) 类型的参数。要在此列上搜索,客户端必须使用指定的密钥和算法加密参数值,以便 SQL Server 可以将确定性加密的列值与加密的参数值匹配。 SQL Server 没有列加密密钥,因此无法解密列值,也无法加密参数值。

SQL Server 具有将加密的表参数传播到存储过程或函数的能力。这个似乎工作正常。要检查存储过程参数是否已拾取列加密,请检查 sys.parameters。 EG

select name, encryption_type_desc, encryption_algorithm_name
from sys.parameters
where object_id = object_id('usp_POListing')

我创建了一个简单的复制,并且能够像这样调用存储过程:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp27
{
    class Program
    {
        static void Main(string[] args)
        {

            using (var con = new SqlConnection("server=localhost;database=testdb;integrated security=true;Column Encryption Setting=enabled"))
            {
                con.Open();

                var sqlCmd = new SqlCommand("usp_POListing", con);
                sqlCmd.CommandType = CommandType.StoredProcedure;

                var param1 = new SqlParameter("@FilterCustomerPO", "G06756");
                param1.SqlDbType = SqlDbType.VarChar;
                param1.Size = 50;
                param1.Direction = ParameterDirection.Input;

                sqlCmd.Parameters.Add(param1);

                var dt = new DataTable();
                using (var rdr = sqlCmd.ExecuteReader())
                {
                    dt.Load(rdr);
                }
            }
        }
    }
}

一般见Develop using Always Encrypted with .NET Framework Data Provider

【讨论】:

  • 所以 - 也许我有一个错误的看法 - 参数化查询与存储过程不同,即使客户端正在添加 SqlParameters?
  • 就这是“客户端”而言 - 不确定这意味着什么 - 该列使用列主密钥(存储在 Azure Key Vault 中)进行加密,在客户端中,我添加了一个 azure key Vault 作为加密的提供者。列主密钥也存储在数据库中(在 Security/Always Encrypted Keys 内)
  • 我想问题是 - sql server(我认为)可以访问密钥,为什么它不能加密?此外,我在这里看到的问题/答案实例表明插入存储过程工作正常。插入物有什么不同吗?
  • 所以 - 我将其标记为答案,因为它帮助我找到了问题 - 本质上,我用小写的“c”键入了参数 - 而不是 @ FilterCustomerPO,我有 @ 987654330@。我不完全是为什么这会导致数据类型冲突,但事实就是如此。
  • 我遇到了同样的问题。当我传递 CustomerId 而不是 CustomerID 时花了我们的(如程序中所写)。值得注意的是,此参数甚至不是由 Always Encrypted 客户端 ADO 驱动程序加密的参数。所以最重要的提示是:检查所有输入参数名称。在这种情况下,错误消息“操作数类型冲突:nvarchar 与使用 (encryption_type = 'RANDOMIZED') 加密的 nvarchar(1000) 不兼容”是无用的。
猜你喜欢
  • 2017-03-09
  • 1970-01-01
  • 2020-10-09
  • 1970-01-01
  • 2018-11-03
  • 2012-06-23
  • 1970-01-01
  • 1970-01-01
  • 2018-05-05
相关资源
最近更新 更多