一、背景
手机号、身份证号等敏感数据不能明文存储,但业务又需要根据这些字段进行精确查询。
一种常见方案是:
敏感数据 → 加密存储
敏感数据 → 哈希 → 查询索引
问题是,查询索引到底应该使用 SHA-256 还是 HMAC-SHA256?
二、两者区别
SHA-256
SHA-256 是不带密钥的哈希算法:
SHA-256(data) → hash
例如:
手机号 → SHA-256 → phone_hash
问题在于手机号、身份证号的取值空间有限。
如果数据库泄露,攻击者可以枚举候选手机号,分别计算 SHA-256,再与数据库中的 Hash 比较,从而进行离线反查。
HMAC-SHA256
HMAC-SHA256 在哈希计算中增加了一个只有服务端知道的 Secret:
HMAC-SHA256(secret, data) → hmac
例如:
手机号 + Secret
↓
HMAC-SHA256
↓
phone_hmac
即使数据库泄露,攻击者没有 Secret,也无法直接按照同样的方式枚举计算。
三、怎么决策?
可以简单按照数据类型和使用场景判断:
| 场景 | 选择 |
|---|---|
| 普通数据摘要、文件完整性校验 | SHA-256 |
| 非敏感数据的 Hash | SHA-256 |
| 手机号、身份证号等低熵敏感数据 | HMAC-SHA256 |
| 敏感字段需要精确查询 | HMAC-SHA256 |
核心判断标准不是:
"SHA-256 安不安全?"
而是:
"攻击者拿到 Hash 后,能不能轻易枚举出原始数据?"
对于手机号、身份证号这种低熵数据,答案通常是可以,因此更适合使用 HMAC-SHA256。
四、实际方案
敏感字段通常采用:
手机号
├── 加密 → phone_cipher // 安全存储
│
└── HMAC → phone_hmac // 精确查询
查询时:
用户输入手机号
↓
HMAC-SHA256(secret, 手机号)
↓
phone_hmac
↓
数据库精确查询
因此可以总结为:
加密解决"怎么安全存储",HMAC-SHA256解决"怎么安全查询"。
而 SHA-256 更适合普通的摘要和完整性校验场景。