做過(guò)金融項(xiàng)目或者政府項(xiàng)目的大佬肯定都實(shí)現(xiàn)過(guò)加密數(shù)據(jù)的模糊查詢功能,大家都是怎么實(shí)現(xiàn)的呢?今天就來(lái)簡(jiǎn)單舉例一些實(shí)現(xiàn)加密數(shù)據(jù)模糊查詢的方案。 | | | | |
|---|
| | | | |
| 數(shù)據(jù)庫(kù)函數(shù)解密 | | | | |
| | | | 大多數(shù)業(yè)務(wù)場(chǎng)景 |
| | | | |
| | | | |
方案1:應(yīng)用層內(nèi)存過(guò)濾
原理
全表查詢加密數(shù)據(jù)
在內(nèi)存中解密后過(guò)濾
public List<User> unsafeSearch(String keyword) { List<User> allUsers = userRepository.findAll(); return allUsers.stream() .filter(user -> decrypt(user.getName()).contains(keyword)) .collect(Collectors.toList());}
致命缺陷:
方案2:數(shù)據(jù)庫(kù)函數(shù)解密
MySQL示例
SELECT * FROM users WHERE AES_DECRYPT(name_encrypted, 'secret_key') LIKE '%張%';
優(yōu)缺點(diǎn):
? 不改動(dòng)業(yè)務(wù)代碼
? 密鑰暴露在數(shù)據(jù)庫(kù)
? 無(wú)法使用索引(全表掃描)
Java安全寫(xiě)法:
@Query(nativeQuery = true, value = "SELECT * FROM users WHERE " + "CONVERT(AES_DECRYPT(name_encrypted, ?1) USING utf8) LIKE ?2")List<User> searchByName(String key, String keyword);
方案3:分詞+密文索引(推薦)
1. 核心思路
2. 代碼實(shí)現(xiàn)
(1). 增強(qiáng)版分詞策略
<dependency> <groupId>com.janeluo</groupId> <artifactId>ikanalyzer</artifactId> <version>2012_u6</version></dependency>
public class EnhancedTokenizer { public static List<String> smartTokenize(String text) { List<String> tokens = new ArrayList<>(); try (StringReader reader = new StringReader(text)) { IKSegmenter seg = new IKSegmenter(reader, true); Lexeme lex; while ((lex = seg.next()) != null) { tokens.add(lex.getLexemeText()); if (lex.getLength() > 1) { for (int i = 2; i <= lex.getLength(); i++) { tokens.add(text.substring(lex.getBeginPosition(), lex.getBeginPosition() + i)); } } } } return tokens.stream().distinct().collect(Collectors.toList()); }}
2. 雙重加密索引表
@Entity@Table(name = "user_search_index")public class SearchIndex { @Id @GeneratedValue private Long id;
@Column(name = "user_id") private Long userId;
@Column(name = "token_hash") private String tokenHash;
@Column(name = "token_cipher") private String tokenCipher;
public static SearchIndex create(Long userId, String token) throws Exception { SearchIndex index = new SearchIndex(); index.setUserId(userId); index.setTokenHash(AESUtil.encryptWithKey(token, "HASH_KEY")); index.setTokenCipher(AESUtil.encryptWithKey(token, "CIPHER_KEY")); return index; }}
3. 智能查詢流程
public List<User> secureFuzzySearch(String keyword) throws Exception { List<String> tokens = EnhancedTokenizer.smartTokenize(keyword);
List<String> hashList = tokens.parallelStream() .map(t -> { try { return AESUtil.encryptWithKey(t, "HASH_KEY"); } catch (Exception e) { throw new RuntimeException(e); } }) .collect(Collectors.toList());
Pageable page = PageRequest.of(0, 100); List<Long> userIds = indexRepository .findUserIdsByTokenHashes(hashList, page);
return userRepository.findAllById(userIds).stream() .filter(user -> { try { String decrypted = AESUtil.decrypt(user.getNameCipher()); return decrypted.contains(keyword); } catch (Exception e) { return false; } }) .collect(Collectors.toList());}
方案4:同態(tài)加密(學(xué)術(shù)級(jí)方案)
基于SEAL庫(kù)的實(shí)現(xiàn)
<dependency> <groupId>com.microsoft.seal</groupId> <artifactId>seal-jni</artifactId> <version>3.7.2</version></dependency>
public class HomomorphicSearch { public static void demo() throws Exception { EncryptionParameters params = new EncryptionParameters(SchemeType.bfv); params.setPolyModulusDegree(4096); params.setCoeffModulus(CoeffModulus.BFVDefault(4096)); params.setPlainModulus(PlainModulus.Batching(4096, 20));
SEALContext context = new SEALContext(params);
KeyGenerator keyGen = new KeyGenerator(context); PublicKey publicKey = keyGen.createPublicKey(); SecretKey secretKey = keyGen.secretKey();
Encryptor encryptor = new Encryptor(context, publicKey); Plaintext plain = new Plaintext("123"); Ciphertext encrypted = new Ciphertext(); encryptor.encrypt(plain, encrypted);
Evaluator evaluator = new Evaluator(context); Ciphertext result = new Ciphertext(); evaluator.add(encrypted, encrypted, result);
Decryptor decryptor = new Decryptor(context, secretKey); Plaintext decrypted = new Plaintext(); decryptor.decrypt(result, decrypted); System.out.println(decrypted); }}
現(xiàn)實(shí)限制:
僅支持有限運(yùn)算(加減/乘)
性能差(單次操作需100ms+)
不支持字符串操作
方案5:可信執(zhí)行環(huán)境(TEE)
基于Intel SGX的解決方案
void ecall_fuzzy_search(const char* encrypted_query, size_t len) { std::string query = decrypt_in_enclave(encrypted_query, len);
sqlite3* db; sqlite3_open(":memory:", &db); std::string sql = "SELECT * FROM users WHERE name LIKE '%" + query + "%'";
encrypt_results(db_exec(sql));}
優(yōu)勢(shì):
硬件級(jí)安全
性能接近明文查詢
挑戰(zhàn):
需要特定硬件支持
開(kāi)發(fā)復(fù)雜度高
閱讀原文:原文鏈接
該文章在 2025/6/14 16:36:35 編輯過(guò)