【问题标题】:How to implement like search in encrypted column JPA specification如何在加密列 JPA 规范中实现类似搜索
【发布时间】:2022-02-01 09:45:37
【问题描述】:

我有一个实体 A 具有以下列定义:

@Column(name = "project_address", nullable = false, length = 500)
@Convert(converter = EncodeDecodeAttribute.class)
private String projectAddress;

EncodeDecodeAttribute.class:

public class EncodeDecodeAttribute implements AttributeConverter<String, String> {
            ...
            @Override
            public String convertToDatabaseColumn(String s) {
                try {
                    if(StringUtils.isEmpty(s))
                        return s;
                    return Base64.getEncoder().encodeToString(encryptCipher.doFinal(s.getBytes()));
                } catch (IllegalBlockSizeException | BadPaddingException e) {
                    log.error("Error convert to database column for value {} with msg {}",s,e);
                    throw new IllegalArgumentException(e);
                }
            }
            
            @Override
            public String convertToEntityAttribute(String s) {
                try {
                    if(StringUtils.isEmpty(s))
                        return s;
                    return new String(decryptCipher.doFinal(Base64.getDecoder().decode(s)));
                } catch (IllegalBlockSizeException | BadPaddingException e) {
                    log.error("Error convert to entity attribute for value {} with msg {}",s,e);
                    throw new IllegalArgumentException(e);
                }
            }
    }

现在我想在列 projectAddress 上实现 like 子句(通配符)和不区分大小写的搜索。

如何做到这一点?

以下是我当前的代码,它仅适用于完全匹配。

public static Specification<A> applyProjectAddressLike(String projectAddress) {
    return ((root, criteriaQuery, criteriaBuilder) ->
            Objects.nonNull(projectAddress) ?
                    criteriaBuilder.like(root.get(A_.projectAddress), projectAddress) :
                    criteriaBuilder.and()
    );

现在如果我将“ABC%”或“%ABC”作为 projectAddress 传递,那么整个单词(包括 %)将被加密,然后 JPA 将运行查询,因此不会得到匹配的结果。

提前感谢您的帮助。

【问题讨论】:

    标签: hibernate encryption spring-data-jpa jpql


    【解决方案1】:

    加密的列没有被索引,也不意味着被看到。 但仍然取决于您的要求,它可以被搜索(但不能使用 JPA),您可以使用 JQL 进行搜索。 有多种方法可以通过它们进行搜索,例如,有另一列将包含已加密名称的哈希值,但您将只能搜索整个文本。并且搜索“ILIKE”更复杂,如下所述: https://dba.stackexchange.com/questions/23908/how-to-search-a-mysql-database-with-encrypted-fields 在我的项目中,我需要使用“ILIKE %something%”进行搜索。对于我的用例来说,实现一棵树太复杂了。我实现这一点的方式是从 java 中运行 SQL/JQL 查询,如下所示:

    String sqlQueryFindUsersByLastName = "select u.* from Users u where CONVERT(AES_DECRYPT(u.lastName, :hashedSecretPhrases) using utf8) like :lastName"
    
    @PersistenceContext
    private EntityManager entityManager;
    
    List<UsersEntity> userEntities = entityManager.createNativeQuery(
                sqlQueryFindUsersByLastName, UsersEntity.class)
            .setParameter("hashedSecretPhrases", AttributeEncryptorConverter.unHexedHash)
            .setParameter("lastName", "%" + lastName + "%")
            .getResultList();

    为了提高性能,请使用 hashedSecretPhrases 作为 byte[]。 如果您在 java 中执行一次并将其发送到数据库,而不是让数据库为您执行每一行(例如 AES_DECRYPT('u.lastName', UNHEX(MD5('some key') )))。 对于您想要的所有其他功能也是如此,例如 LOWER,保持 sql 短语尽可能简单,无需操作.. 当然,您需要考虑到 CONVERT(AES_DECRYPT 将比查询常规索引列花费更多时间,因此此解决方案取决于您的用例。如果它不适合您的用例,请阅读我附加的链接和以最适合的方式实施。

    【讨论】:

      猜你喜欢
      • 2019-08-12
      • 2018-11-01
      • 2021-06-05
      • 2011-03-10
      • 2019-12-01
      • 2018-04-08
      • 2012-04-29
      • 1970-01-01
      • 2020-10-18
      相关资源
      最近更新 更多