4. 令牌化类型深度解析:FPE vs Non-FPE
说实话,很多人一上来就问我:“令牌化不就是把敏感数据换成一串随机数吗?” 我刚开始也这么想。直到我在银行项目里,遇到一个必须保持信用卡号格式的合规要求——原数据是16位数字,脱敏后还得是16位数字,不能出现字母。这时候我才明白,令牌化没那么简单。
咱们这次聊的两个类型,说白了就是:FPE(Format-Preserving Encryption) 和 Non-FPE(非格式保留令牌化)。一个要“长得像”,一个无所谓。怎么选?往下看。
4.1. 什么是格式保留令牌化(FPE)
FPE,全称 Format-Preserving Encryption。它的核心就是你输入“1234-5678-9012-3456”,输出还是4组4位数字,中间有分隔符,长度不变。我习惯叫它“整容不变脸”——数据变了,样子没变。
为什么需要它?举个例子:你有个老系统,数据库字段写死了“信用卡号必须是16位数字,带连字符”。你要是给它换成32位随机字符串,系统直接报错。FPE就是为解决这种兼容性问题诞生的。
FPE的典型算法
- FF1(NIST SP 800-38G):基于Feistel网络,支持任意字母表(数字、字母、符号)。我最常用它处理身份证号、护照号。
- FF3-1(NIST修订版):速度更快,但最小输入长度有限制(比如至少2个字符)。我一般在处理较短字段(如邮编)时用。
- VAES3(Volt 套件):商业实现,适合高性能场景。我在高并发API网关里见过它的影子。
FPE的优缺点
| 维度 | 优点 | 缺点 |
|---|---|---|
| 兼容性 | 不改数据库Schema,零侵入 | 对格式有严格要求,无法处理长度变化 |
| 安全性 | 可逆(有密钥就能还原),适合合规审计 | 密钥泄露则全量暴露 |
| 性能 | 算法成熟,硬件加速友好 | FF1/FF3-1在长字段上略慢于对称加密 |
| 适用场景 | 信用卡、手机号、身份证、社会安全号(SSN) | 不适合格式不固定的文本(如邮件地址) |
4.2. 什么是非格式保留令牌化(Non-FPE)
Non-FPE 就简单多了。你输入“abc@example.com”,输出可能是“tok_8f3a9b2c”。长度变了,格式变了,甚至加了前缀。说白了,它不关心“原数据长什么样”。
我个人习惯把 Non-FPE 用在数据湖、分析库、日志脱敏场景里。为什么?因为这些地方不需要保持格式,反而希望令牌尽可能短(节省存储),或者加一些元信息(比如前缀标识来源)。
Non-FPE的常见实现方式
- 随机令牌生成:直接生成UUID或随机定长字符串,与原始数据做映射表。我最常用的方式,简单、安全。
- 哈希+盐值:SHA-256 + 随机盐,截取前N位。注意:不可逆,适合静态脱敏。
- AES-GCM-SIV + 截断:保留高级加密的可逆性,但输出是二进制,要Base64编码后再截断。我在日志脱敏项目里用过。
Non-FPE的优缺点
| 维度 | 优点 | 缺点 |
|---|---|---|
| 灵活性 | 长度、格式自由,可加前缀/后缀 | 无法兼容老系统的格式校验 |
| 安全性 | 映射表+密钥双重保护,可细粒度控制访问 | 映射表可能成为性能瓶颈 |
| 性能 | 生成速度快,适合大规模流式处理 | 高频查询时,映射表查找有延迟 |
| 适用场景 | 数据仓库、日志、API网关、用户ID脱敏 | 不适合支付卡号、IBAN等必须保留格式的字段 |
4.3. 怎么选:FPE vs Non-FPE 对比总结
你可能会问:“那我到底用哪个?” 嗯,这里要注意。我的经验是:别纠结于“哪个更安全”,安全级别可以用密钥长度和算法强度达成一致。真正的分水岭是格式要求和系统兼容性。
下面这张表我每次做方案设计都贴在白板上,你直接拿去用。
| 判断条件 | 选 FPE | 选 Non-FPE |
|---|---|---|
| 下游系统是否校验格式? | 是(例如:卡号校验、身份证校验) | 否(纯存储、分析、日志) |
| 是否需要保留原字段长度? | 是 | 否 |
| 令牌是否需要可逆? | 是(FPE天生可逆) | 可逆/不可逆都行(映射表决定) |
| 性能要求高吗? | 中等(算法有计算开销) | 高(简单随机生成,很快) |
| 是否需要跨系统一致性? | 是(同一密钥,同一算法,全局一致) | 否(映射表各自独立) |
我个人习惯这样定策略:
- 核心支付敏感字段(卡号、CVV、有效期)→ 必须用 FPE。因为PCI-DSS要求你“无法从格式上识别出信用卡”,但系统又要保持格式。
- 个人身份信息(姓名、邮箱、电话)→ 首选 Non-FPE。因为这些字段格式各异,保持原样没意义。我在用户画像项目里就是这么干的。
- 混合场景(既有结构字段又有非结构字段)→ 分开处理:结构化用FPE,非结构化用Non-FPE。记得用不同的密钥空间。
最后,说一个很多人容易犯的错。你想想看,如果FPE算法选错了参数(比如字母表定义不完整),可能会触发不可逆的错误。我曾经遇到一个案例:同事把字母表写成“0-9”,结果输入字段里有个字母,FPE直接报错。所以,用FPE前,必须精确理解你字段的合法字符集和长度边界。
总结一下:FPE 和 Non-FPE 没有好坏之分,只有合不合适。我自己的项目中,80% 的字段用的是 Non-FPE(因为大部分是内部分析和日志),只有 20% 的核心字段我会用 FPE。你根据你的业务预期,对号入座就行。