加密字段模糊搜索
导读
加密字段由于“雪崩效应”特性,无法直接进行 SQL 模糊查询,但在实际业务中往往有脱敏字段的模糊搜索需求。本文介绍主流的安全实现思路(分片哈希索引法),兼顾安全与业务需求,并提供代码与原理讲解实现“加密字段模糊搜索”。
背景
敏感信息(如手机号、身份证号、银行卡号、地址等)加密后无法直接使用 SQL 的 LIKE ‘%xxx%’ 进行模糊搜索,因为加密是“雪崩效应”的:明文微小变化 → 密文完全不同,且密文长度/格式通常与明文不一致。
但是如果业务需要,输入 6688 查出手机号包含 6688 的用户,我们需要采用特殊的方式解决。
1. 分片+索引
将明文按固定长度滚动切片 → 对每个片段用 HMAC(带密钥哈希) 生成指纹 → 存入索引表。查询时对关键词同样切片+HMAC,匹配索引。
存储时:
- 原文为
13866889900,在内存中对原文进行滚动分片按,长度 3 滚动切片:138,386,866,668,688,889,899,990,900。 - 对每个分片计算HMAC-SHA256
1 | |
- 加密后原文存表
1 | |
- 加密后切片存表
1 | |
- 查询时输入
6688,切片len=3,为668,688,计算两个切片的HMAC-SHA256,通过子查询或者内联查询
1 | |
或者
1 | |
找到同时包含两个切片的结果。
6. 在返回结果时,为防止哈希碰撞或非连续匹配,在内存中返回
1 | |
特点:
- 支持前中后模糊搜索
- 需要切片长度>=3
2. 确定性加密+索引前缀
适用于 只支持“前缀搜索” 的场景(如查手机号 138%)
- 使用确定性加密算法(对同一原文,每次加密的结果相同)
如AES-SIV等。 - 对明文的每个前缀单独加密存储,对于原文
13866889900 - 存储:
enc("1"),enc("13"),enc("138"), …,enc("13866889900") - 查询
138%,计算enc(138)
特点
- 仅限前缀搜索
- 每一条原文都需要增加
n条记录
错误做法
- 加载全量数据到内存解密再匹配,会导致OOM问题,数据量大时不可用。
- 数据库内置解密函数并使用Like:
SELECT * FROM t WHERE AES_DECRYPT(col) LIKE '%6688%',会导致全表扫描,性能极差;密钥暴露给 DBA。
加密字段模糊搜索
https://yicizhang00.github.io/posts/编程语言/Java/工程实践/加密字段模糊搜索/