2

在 SQL Server 2012 数据库中,我有一个包含 varbinary(128) 列的表,该表存储由证书 (AppCert) 支持的密钥 (Secret_Key) 和使用主键的 SHA2_512 哈希的身份验证器加密的数据:

CREATE TABLE [Lookup].[SecretStuff] (
    [Id] tinyint NOT NULL, 
    [Secret] varbinary(128) NOT NULL
        CONSTRAINT [PK_Lookup-SecretStuff_Id] PRIMARY KEY CLUSTERED ([Id] ASC), 
        CONSTRAINT [UN_Lookup-SecretStuff_Secret] UNIQUE NONCLUSTERED ([Secret])
);

OPEN SYMMETRIC KEY [Secret_Key] DECRYPTION BY CERTIFICATE [AppCert];
INSERT INTO [Lookup].[SecretStuff] ([Id], [Secret]) VALUES (1, ENCRYPTBYKEY(KEY_GUID('Secret_Key'), CONVERT(nvarchar(512), 'I have a secret'), 1, HASHBYTES('SHA2_512', CONVERT(varbinary(128), CONVERT(tinyint, 1)))));
CLOSE SYMMETRIC KEY [Secret_Key];

OPEN SYMMETRIC KEY [Secret_Key] DECRYPTION BY CERTIFICATE [AppCert];
SELECT [Id], CONVERT(nvarchar, DECRYPTBYKEY([Secret], 1, HASHBYTES('SHA2_512', CONVERT(varbinary, [Id])))) AS [Secret] FROM [Lookup].[SecretStuff];
CLOSE SYMMETRIC KEY [Secret_Key];

这一切都很好。现在,我有一个使用 JPA/Hibernate 的 Spring Boot 应用程序,该应用程序已连接并经过测试/验证以与该数据库一起使用。SecretStuff 类:

@Entity
@Table(name="SecretStuff", schema="Lookup")
public class SecretStuff {

    @Id
    @Column(name = "Id", 
            nullable = false)
    private Integer id;

    @Column(name = "Secret", 
            nullable = false, 
            unique = true)
    @Size(min = 1, max = 255)
    @ColumnTransformer(
            read = "CONVERT(nvarchar(89), DECRYPTBYKEY([Secret], 1, 
                    HASHBYTES('SHA2_512', CONVERT(varbinary(128), [Id]))))")
    private String secret;
// getters/setter omitted
}

当我测试 SecretStuff 类时,我看到以下 Hibernate 生成的 SQL:

select
    secretstuf0_.Id as Id1_7_0_,
    CONVERT(nvarchar(89), DECRYPTBYKEY(secretstuf0_.[Secret],
    1,
    HASHBYTES('SHA2_512',
    CONVERT(varbinary(128),
    secretstuf0_.[Id])))) as Secret2_7_0_ 
from
    Lookup.SecretStuff secretstuf0_ 
where
    secretstuf0_.Id=?

执行并返回 Id = 1 Secret = NULL 的 1 行的完全合理的查询,因为在执行查询之前未打开 SYMMETRIC KEY。

我的问题: 如何在查询之前在同一事务中执行 OPEN SYMMETRIC KEY... 命令,在查询之后在同一事务中执行 CLOSE SYMMETRIC KEY... 命令?

我在服务类方法中使用了 Hibernate.initialize 来延迟获取事务中的多对多关系。我会在这里使用类似的方法吗?如何?

我在输入这个问题时看到了这篇文章,但它已经有几年历史了,并且使用了 NativeQuery 的 EntityManager 方法。有没有更新的方法来使用 JPA/Hibernate 来管理这个?

4

1 回答 1

2

虽然不是我正在寻找的确切解决方案,但我在原始问题中引用的文章和@TrevorAbell的一些帮助引导我找到了以下似乎适合我需要的代码。我在这里发布它以防其他人正在寻找类似的解决方案。我仍然对其他解决方案持开放态度。

关键是使用 EntityManager 围绕查询运行 SYMMETRIC KEY 命令。为了完整起见,我将包含@Repository 接口和@Service 类,但关键是@Service 类:

@Repository
public interface SecretStuffRepository extends JpaRepository<SecretStuff, Integer> {}

@Service
@Transactional(readOnly = true)
public class SecretStuffService {

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private SecretStuffRepository repository;

    public Iterable<SecretStuff> findAll() {

        this.entityManager.createNativeQuery("
              OPEN SYMMETRIC KEY [Secret_Key] 
              DECRYPTION BY CERTIFICATE [AppCert];
          ").executeUpdate();
        Iterable<SecurityQuestion> questions = this.repository.findAll();
        this.entityManager.createNativeQuery("
              CLOSE SYMMETRIC KEY [Secret_Key];
          ").executeUpdate();
        return stuff;
    }
}

现在,当我测试 SecretStuffService 时,我看到以下 Hibernate 生成的 SQL:

Hibernate: 
    OPEN SYMMETRIC KEY [Secret_Key] DECRYPTION 
BY
    CERTIFICATE [AppCert];
Hibernate: 
    select
        secretstuf0_.Id as Id1_5_0_,
        CONVERT(nvarchar(89),
        DECRYPTBYKEY(secretstuf0_.[Secret],
        1,
        HASHBYTES('SHA2_512',
        CONVERT(varbinary(128),
        secretstuf0_.[Id])))) as Secret2_5_0_ 
    from
        Lookup.SecretStuff secretstuf0_ 
    where
        secretstuf0_.Id=?
Hibernate: 
    CLOSE SYMMETRIC KEY [Secret_Key];

调用 SecretStuffService.findAll() 现在打开密钥,调用存储库 findAll() 方法,并关闭同一事务中的密钥。请记住,本例中的 NativeQuery 特定于 Microsoft SQL Server,因此您需要为您的数据库供应商替换适当的命令。

于 2016-10-20T21:00:07.747 回答