Skip to content

加密后的数据怎么支持模糊搜索? ​

  • 标签:后端、系统设计、场景题

🏛 业务架构师 ​

加密后的数据怎么支持模糊搜索——这是加密可用性的经典矛盾,我先定调:先问业务到底要什么样的"模糊",90% 的"模糊搜索"其实只是"等值查询 + 后缀匹配",把需求问清,方案可以从重到轻砍掉一半成本。

需求分层(先做需求裁剪)

  • 等值查询(输入完整手机号找用户):不需要"模糊"——盲索引方案
  • 后缀/片段匹配(输入尾号 4 位找用户):电话场景的绝对主流
  • 任意子串模糊(输入中间任意几位):真正的难题,方案最贵

方案一:盲索引(等值查询的标准解)

存储列: ciphertext = AES(手机号)
索引列: idx = HMAC(server_key, 手机号)
查询: WHERE idx = HMAC(server_key, 输入)   -- 精确命中索引

密文不可逆查询?把查询词同算法转成索引值即可等值匹配。多格式手机号(+86/带空格)要先归一化再算索引,否则查不到。

方案二:分片索引(尾号/片段匹配)

把手机号切段,每段单独算盲索引存索引表:尾 4 位一段、中间 4 位一段——查询时定位段索引再精筛。段粒度是安全与功能的权衡(段越短越易被字典攻击反推)。手机号后 4 位是客服场景的绝对主流,这一档能覆盖。

方案三:真正的任意模糊(重方案,按需选用)

  • 密文数据库(如 CryptDB 思路、国产密态数据库):OPE/保序加密支持范围查询,但安全强度有争议、性能损耗大
  • 专用搜索加密(SSE)/ 侧行解密:单独一个授权搜索服务持有密钥做明文检索,返回脱敏结果——工程上"受控的明文域"往往比炫技密码学更实用
  • ES 明文索引 + 严格权限审计:承认索引必须明文,把安全重心放在访问控制——务实派做法,配合最小权限 + 审计告警

收尾(架构师观点):我的选型顺序是盲索引 → 分片索引 → 受控明文域,密态数据库除非合规强制不上——安全和可用性的平衡点由业务查询频率决定:高频客服查询值得受控明文域 + 审计,低频场景宁可直接人工。

🏗 系统架构师 ​

加密后模糊搜索的核心矛盾:加密破坏了明文的顺序与结构,而 LIKE 需要明文连续性。我给五个方案,按场景选。

1. 分词索引表(工程上最常用) 手机号场景:预计算明文的片段哈希存独立索引表。搜 138 开头:把搜索词 138 hash 后查索引表命中记录 ID,再回表解密精确比对:

text
sensitive_index(user_id, fragment_hash)
写入时:hash('138')、hash('1380')、hash('13800')... 前缀分段入索引
查询时:WHERE fragment_hash = hash(搜索前缀) → 命中 → 解密校验

手机号只需前缀索引(前 3 位、前 7 位),身份证同理分段。密文本身仍在主表加密存储,索引表只存"哈希化的片段",攻击者拿不到明文规律。

2. 数据库原生加密函数(MySQL 8.0+ AES)AES_ENCRYPT 存二进制 + 生成列存 FROM_BASE64(AES_ENCRYPT(...)) 前 n 位——本质还是方案 1 的数据库实现。

3. 专门的模糊加密算法(学术前沿,特定场景)

  • 对称可搜索加密(SSE):支持等值与受限模糊匹配,适合外包存储场景
  • 保序加密 OPE / 有限泄漏的 FPE(格式保留加密):FPE 加密后手机号还是 11 位数字,且保留了受控的等值查询能力;OPE 保序但泄漏量大,仅用于范围查询需求且低敏感字段
  • 这些方案有泄漏轮廓(leakage profile)问题,用之前要安全评估

4. 专门的检索服务 敏感数据同步到独立的加密检索服务/ES:ES 里存脱敏降级数据 + 分词哈希,主库只有密文——检索域与存储域分离,权限与审计集中。

5. 交互模式改造(产品层解法) 很多时候"模糊搜索手机号"可以改为精确搜索:用户输入完整手机号(一次性哈希后等值查询加密列——确定性加密支持等值)或通过"姓名+证件号"等组合精确定位。把模糊需求消灭在产品设计,是成本最低的方案。

我的选型:手机号/证件号用前缀分段哈希索引表(方案 1)最稳;姓名类(任意字符 LIKE)上独立检索服务;同时评估产品上能否改精确查询。

💻 全栈开发专家 ​

直接说结论:密文上做模糊搜索没有完美方案,工程上按查询需求分层处理——等值走 HMAC 列、后缀/前缀走截断哈希、真模糊走分词索引或专用密文检索。

等值查询:HMAC 辅助列

sql
phone_enc  VARCHAR -- AES-GCM 密文
phone_hmac CHAR(64) -- HMAC_SHA256(key, phone),等值查询走这列
SELECT * FROM t WHERE phone_hmac = ?; -- 客户端先算 HMAC 再查

手机号后 4 位查询(最常见需求)

单独存脱敏低敏列 phone_suffix VARCHAR(4) 明文(或它的 HMAC),后 4 位敏感度低、可用性高,是客服系统的标准做法:

sql
WHERE phone_hmac = ? -- 精确
WHERE phone_suffix = '1234' -- 后缀

姓名模糊(LIKE '%张%')

把明文按字/二元组切分,逐个 HMAC 后存集合字段(JSON 或独立关联表),查询同样切分:

text
存储:{"h(张), h(张三)"}  -- 单字 + 二元组
查询 LIKE '%张%' → WHERE tokens CONTAINS h(张)

MySQL 8 JSON 字段或 ES 的 token 字段都行,能覆盖"包含某字"类查询,代价是存储翻倍、只支持已知模式(前缀通配 %张 可以用二元组覆盖,任意通配组合不行)。

范围/任意模糊:上密文检索方案

  • 可信执行环境:如密文数据库(CubeFS 加密态、阿里云全密态数据库 RDS MySQL 版),密文态下服务器执行查询。
  • ES + 字段级加密插件,或干脆"低敏索引列明文 + 高敏列密文"的组合(如姓名首字母明文做索引)。

我给面试官的 trade-off 总结:安全性和可用性成反比——先问清楚业务到底有几种查询模式,能用等值 + 后缀解决就别上全模糊;真要全模糊,全密态数据库或专用密码学方案(如 ORE 有序加密)成本要讲清楚。