常见令牌化方案
聊令牌化方案,绕不开两个东西:PCI DSS 和 Vaultless vs Vaulted。
PCI DSS,说白了就是支付卡行业的数据安全标准。你只要是做支付相关的系统,就一定得跟它打交道。我这些年做过的合规项目,十个里有八个都跟PCI DSS脱不了干系。
至于Vaultless和Vaulted——这是两种截然不同的令牌生成思路。一个轻量,一个厚重;一个讲究算法,一个依赖存储。
先看PCI DSS令牌化
PCI DSS对持卡人数据(CHD)的保护有严格规定。其中一条很要命:禁止存储完整的磁条数据、CVV2和PIN。但业务又要跑,怎么办?令牌化就是答案。
你想想看,我拿卡号,生成一个令牌。令牌能用来做交易、查订单、走退款,但拿到令牌的人反推不出卡号。这不就合规了么?
核心逻辑:用令牌替代真实的PAN(Primary Account Number),让令牌在业务系统中流转,真实PAN牢牢锁在HSM或保险箱里。
什么是合格的令牌?我个人习惯看三点:
- 不可逆——从令牌不能算出PAN,除非你有密钥和HSM。
- 无意义——令牌本身不带卡BIN、校验位等敏感模式。
- 域限制——令牌只能在发卡系统内部使用,出了域就是废纸。
我见过有的团队直接用PAN的SHA256哈希当令牌,结果被PCI审计直接卡住。为什么?哈希虽然不可逆,但暴力枚举卡号空间完全可行。你猜我后来怎么解决的?加了一个HSM派生密钥,再做HMAC。
Vaulted模式(又称有库令牌化)
Vaulted,就是建立一个中央令牌库。每个令牌对应一条记录,记录里存着PAN、有效期、令牌本身。你拿着令牌来查库,库给你真实PAN。这叫查表法。
我在项目中使用过最常见的Vaulted方案:
- 数据库里一张
_mapping表,字段大概就是_id, pan, expires_at, created_at。 - 真实PAN加密存储,解密密钥放在HSM里。
- 令牌本身可以是随机UUID或雪花ID。
-- 这是个简化的_mapping表结构
CREATE TABLE _mapping (
_id VARCHAR(64) PRIMARY KEY,
pan_enc VARBINARY(256) NOT NULL, -- HSM加密后的PAN
pan_fp VARCHAR(64) NOT NULL, -- 用于查重的指纹,HMAC-SHA256
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
这种方案的好处很明显:
- 令牌生成快——纯粹是一次INSERT。
- 令牌可以取消——删掉映射记录,令牌立刻失效。
- 支持大规模并发——只要数据库扛得住。
但坑也有。我曾经遇到一个支付平台,令牌库每天写入上千万条记录,到最后单表查询慢得不行。你以为加索引就能解决?错了,令牌映射查的是令牌字段,你建的索引覆盖不了所有查询模式。最后还是分表+Redis缓存才救回来。
另一个隐患是库的可用性。令牌库一旦挂了,所有依赖令牌的业务都得停。那你问我怎么办?一般做法是主从、多活、加上本地缓存。
Vaultless模式(又称无库令牌化)
Vaultless,就是不依赖中央数据库。令牌本身是一个自包含的数据结构,里面藏了PAN的部分信息,但加了强加密和完整性校验。拿到令牌后,用HSM的密钥解密,就能还原出PAN。
说白了,Vaultless就是加密+格式保留加密(FPE)的变体。常见的两种算法:
- FF1 / FF3-1——NIST标准,保留明文格式和长度。
- AES-CBC + 签名——非保留格式,但更安全。
# 一个伪代码级别的Vaultless令牌生成流程
def generate_(pan, hsm_key_id):
# 1. 从HSM获取派生密钥
dek = hsm.derive_key(hsm_key_id, pan_bin[:4] + pan_bin[-4:])
# 2. 用FPE加密PAN中间部分
encrypted_pan = fpe_encrypt(pan, dek, tweak=txn_id)
# 3. 拼接令牌结构:前6位明文 + 加密中间 + 后4位明文 + 签名
= pan[:6] + encrypted_pan[6:-4] + pan[-4:]
+= hmac(dek, )[:8].hex()
return
这种方案的优势:
- 零存储——令牌自己不依赖数据库。
- 低延迟——脱令牌只需要HSM解密,一次网络交互就够。
- 无限扩展——没有库容量上限。
不过也别高兴太早。Vaultless的弱点也很要命:
- 令牌不是随机生成的——同卡号在不同时段生成的令牌,可能部分重复。
- 一旦密钥泄露——所有令牌都能被逆向。
- 吊销困难——你不能删除某个令牌,只能更新密钥,但更新密钥会让所有旧令牌失效。
两张方案的对决
我直接列个对比表,你看哪个更适合你的场景:
| 维度 | Vaulted(有库) | Vaultless(无库) |
|---|---|---|
| 存储依赖 | 强依赖令牌库 | 无需持久化存储 |
| 令牌可逆性 | 查库即可还原 | 必须走HSM解密 |
| 吊销令牌 | 删除映射记录即可 | 需要全量密钥替换 |
| 性能瓶颈 | 数据库IO | HSM加解密 |
| 合规难度 | 库中加密PAN需定期轮换 | 密钥管理和算法审核 |
| 常见场景 | 电商、订阅、退款场景 | 收单、快捷支付、低延迟交易 |
我个人的选型建议
做选型其实没那么玄乎。我一般这样判断:
- 如果我的业务需要频繁吊销令牌(比如风控要求阻止某张卡),我会选Vaulted。
- 如果我的业务追求极致吞吐,而且令牌数量可以预见会爆炸式增长,我会选Vaultless。
- 如果我的客户对数据主权有强制要求(比如泛金融监管),Vaulted更可控。
我记得在做一个东南亚支付项目时,当地监管要求令牌必须与卡号对等可溯源。我们落地的是Vaulted + HSM加密库+定期审计。另一个北美电商项目就不一样了,直接用Vaultless,因为商家只关心支付完成,不关心令牌能不能取消。你看,场景不同,选择完全不同。
一张图看懂两种模式
下面这张SVG,我画了Vaulted和Vaultless的完整流程对比。节点用深色区分,箭头代表数据流向,说明框放关键差异。你仔细看,应该能一眼看出两种模式的本质区别:
最后聊几句安全红线
不管选哪种,有几个红线不能碰:
- 令牌不能包含PAN明文片段——除了格式保留令牌的固定段(比如前6后4),其余必须混乱或加密。
- 密钥必须独立——令牌生成密钥和生产加密密钥不能共用。我曾经在一个项目中发现测试环境和生产环境用了同一个HSM密钥组,差点出事故。
- 审计日志要全——谁、什么时间、通过什么接口、请求了多少次令牌还原,全都要记下来。
重中之重:无论Vaultless还是Vaulted,都不能让自己的HSM密钥变成明文配置文件。我见过最夸张的是一位开发者把HSM密钥硬编码在Gradle配置里上传到GitHub,三分钟内就被爬虫抓走。你想想看,这得多吓人。
好了,关于常见令牌化方案的核心内容基本就这些。PCI DSS是底线,Vaulted和Vaultless是工具,你得清楚自己的业务场景,才不会选错。