在始终加密的 SQL Server 数据库上调用存储过程

问题描述 投票:0回答:1

从始终加密的 SQL Server 数据库调用任何存储过程时,出现以下错误:

SQLServerException:传入的表格数据流(TDS)远程过程调用(RPC)协议流不正确。参数 1 (""):数据类型 0xC0 未知。

表和存储过程是这样创建的:

CREATE TABLE [dbo].[test_table] (
    [id] [int] IDENTITY(1,1) NOT NULL,
    [encrypted_col] [nvarchar](255) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [MY_KEY], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL
)
GO

CREATE PROCEDURE [dbo].[test_sp]
    @test_param nvarchar(255)
AS
    SELECT * from test_table where encrypted_col = @test_param
GO

java代码如下所示:

try(CallableStatement callableStatement = connection.prepareCall("{call test_sp(?)}")) {
    callableStatement.setNString(1, "TEST VALUE");
    ResultSet rs = callableStatement.executeQuery(); <-- Throws the Exception
}

我的连接网址如下所示:

jdbc:sqlserver://localhost:1433;applicationName=MY-APP;databaseName=test_encryption;sendStringParametersAsUnicode=false;encrypt=true;trustServerCertificate=true;columnEncryptionSetting=enabled;enclaveAttestationUrl=http://localhost/Attestation;enclaveAttestationProtocol=HGS;

导致此错误的原因是什么?

备注:

  • 我正在使用 SQL Server 2019 和最新的 mssql 驱动程序 (12.6),它们兼容。我也尝试降级驱动程序,但导致了同样的错误。
  • 使用 Hibernate 从数据库表读取数据或向数据库表写入数据,这让我认为连接 URL 和加密密钥设置正确。我只在存储过程中收到此错误
  • 可以从SQL Server Management Studio成功调用存储过程,这让我认为在数据库级别正确创建了过程和加密
  • 我尝试了其他几种调用存储过程的方法,例如使用 Hibernate Query 或 Spring Jpa Query,但它们都会导致相同的错误。
  • 如果我在不使用加密的情况下重新创建数据库表,则调用存储过程可以工作
  • 我尝试将数据库连接参数 sendStringParametersAsUnicode 与 false 和 true 值一起使用
java sql-server always-encrypted
1个回答
0
投票

解决方法

我找到了一种解决方法,即使用PreparedStatement 并在sql 查询字符串中手动声明参数类型。示例:

String sql = "declare @test_param nvarchar(255) = ?;" +
             "exec test_sp @p1";

PreparedStatement statement = connection.prepareStatement(sql);
statement.setNString(1, "test");
ResultSet rs = statement.executeQuery();

如果没有在 SQL 字符串中手动声明参数类型,数据库似乎无法将参数类型与包含正在搜索的值的列的类型进行匹配。

© www.soinside.com 2019 - 2024. All rights reserved.