本文目录导读:

银行卡号的脱敏,核心原则是在保留必要信息(如后四位用于核对)和隐藏敏感信息(中间数字)之间取得平衡。必须确保脱敏后的数据无法被逆向还原。
以下是几种常见且安全的脱敏方法及注意事项:
常用的脱敏规则
最常见、最符合用户认知习惯的是 保留前六位和后四位。
- 前六位:发卡行识别码,用于标识银行和卡种,在业务流程中通常可以公开。
- 后四位:用于用户核对、交易确认。
- 中间部分:用星号 、
x或 替代。
示例:
- 原始卡号:
6222 0200 1234 5678 - 脱敏后:
6222 02** **** 5678
其他变体(安全性更高):
- 只保留后四位:
**** **** **** 5678(适用于仅需用户确认的场景,如支付成功页) - 展示前四位+后四位:
6222 **** **** 5678
不同类型场景的脱敏策略
根据用户或系统的不同访问权限,可以设置不同级别的脱敏:
| 场景 | 用户视角 | 客服/后台操作 | 数据库存储 |
|---|---|---|---|
| 用户端展示 (App/网页) | 仅展示后四位 (如 ...5678) 或 完整后四位+卡组织图标 |
不展示完整卡号 | 不存储明文 |
| 交易记录/详情 | 6222 02** **** 5678 |
6222 02** **** 5678 |
仅存储脱敏后的哈希值或加密值 |
| 原始数据传输 (API/日志) | 不涉及 | 必须遮盖 或使用加密通道,禁止打印完整卡号 | 内部系统间使用令牌化或加密传输 |
安全实现的注意事项
- 不可逆性:脱敏不是加密,加密(如AES)可以被解密,脱敏后的数据应永久丢弃原始信息。不要在系统中同时存储原始卡号和脱敏规则,以防泄露。
- 一致性:对同一个原始卡号,无论何时、由谁处理,脱敏后的结果必须相同,这可以通过动态脱敏或基于摘要的脱敏实现。
- 避免模式识别:不要只在中间固定位置替换(例如只替换第7-10位),这样会暴露卡号的长度信息和部分校验位,建议使用“保留首尾+中间通配”的固定模式。
- 动态脱敏 vs. 静态脱敏:
- 静态脱敏:在存储或导出时直接修改数据,优点是安全,但原始数据会被永久覆盖或隔离。
- 动态脱敏:在数据输出(如API、页面渲染)时,根据用户权限实时替换,原始数据仍安全存储在数据库或加密区。
- 推荐:生产环境中建议使用动态脱敏,并配合数据访问控制(只有极少数高级权限才能看到完整卡号)。
实际代码示例(Python)
import re
def mask_bank_card(card_number: str) -> str:
"""
对银行卡号进行脱敏,保留前6位和后4位,中间用星号填充。
输入格式:纯数字或带空格。
"""
# 1. 清理输入,移除所有非数字字符
cleaned = re.sub(r'\D', '', card_number)
# 2. 校验长度(国内银行卡通常16-19位)
if len(cleaned) < 10:
# 长度过短,无法脱敏(可以返回部分遮蔽或报错)
return f"****{cleaned[-4:]}" if len(cleaned) >= 4 else cleaned
# 3. 提取前6位和后4位
start = cleaned[:6]
end = cleaned[-4:]
# 4. 计算中间需要遮蔽的位数
middle_len = len(cleaned) - 10
middle = '*' * middle_len
# 5. 组合结果,并添加空格分割(可选)
masked = f"{start} {middle} {end}"
return masked
# 测试
print(mask_bank_card("6222020012345678")) # 输出: 622202 ****** 5678
print(mask_bank_card("621700 1234 5678 901")) # 输出: 621700 **** 8901
- 最安全直观:展示后四位,其他全部遮蔽。
- 业务常用:保留前六位和后四位,中间用星号填充。
- 核心原则:不可逆、能少展示就少展示、权限最小化。
重要提醒:脱敏后,如果还需要使用原始卡号进行交易(如支付、预授权),绝不能依赖脱敏后的数据,必须使用加密存储、令牌化或硬件安全模块(HSM)等技术保护原始卡号,脱敏只是面向用户展示的“面子”,底层数据安全需要另外的体系。