第2章:PAN数据识别与敏感数据分类标准

说来也简单,保护PAN的第一步,得先知道哪些数据是PAN。

你想想看,一个支付系统里,上下游流转的字段少说几十个。卡号、有效期、CVV、持卡人姓名、设备指纹、令牌...你得清楚它们各自的敏感等级,才能决定“谁该进保险柜,谁放前台就行”。

这一章,我们就来梳理这件事。

2.1 什么是PAN数据

PAN 的全称是 Primary Account Number,也就是主账号。说白了,就是银行卡正面那串16-19位的数字。

但问题没这么简单。PCI DSS(支付卡行业数据安全标准)对“PAN数据”的定义,远不止卡号本身。

我习惯把PAN相关的数据按“是否可直接用于交易”分成两组:

数据项 是否属于PAN 能否明文存储 典型示例
卡号 (PAN) 是 否,必须加密或令牌化 4111111111111111
到期日期 是 否,需保护 12/28
CVV2/CVC2 是 否,交易后禁止存储 123
持卡人姓名 否 可明文,但建议保护 ZHANG SAN
服务代码 否 可明文 101
磁道数据 是(含PAN) 否,仅限发卡行保留 %B411111...^
注意: 很多团队容易忽略“磁道数据”和“有效期”的敏感度。我在项目中遇到过,系统把有效期当普通字段直接写日志,结果PCI审计直接亮了红灯。记住,只要能和卡号组合用于交易的,都得按敏感数据管。

2.2 敏感数据分类标准

光知道哪些是PAN还不够。你得有一套标准,告诉团队:这个字段到底有多“敏感”。

我个人习惯把支付数据分成四个等级。这个分级不是PCI强制的,但几乎所有我参与过的令牌化项目都这么用。

2.2.1 四级分类模型

等级 定义 典型字段 存储要求
L1 - 极高 可直接完成交易的数据 PAN、磁道数据、芯片数据 必须令牌化;不可明文存储;传输强制加密
L2 - 高 配合PAN可完成交易的数据 到期日期、CVV2、持卡人姓名 建议令牌化或加密;日志中脱敏
L3 - 中 业务关联数据,不可单独交易 令牌()、交易金额、商户ID 需访问控制;可明文但建议加密
L4 - 低 非敏感元数据 交易时间、设备型号、网络IP 常规安全策略即可

这个分类有什么用?

举个例子。你设计令牌服务API的响应体时,L1和L2字段不允许原样返回。但L3的值可以返回,只不过要加个认证签名防篡改。L4的字段,甚至可以直接明文透传。

2.3 如何自动识别PAN数据

理论上,人工标注一遍字段就够了。但现实是,支付系统里每天有大量动态数据进来,尤其是来自第三方网关的响应报文。你不能每次手工去翻日志找。

我建议在API网关或ESB层,加一个“数据识别中间件”。

2.3.1 正则识别

最直接的办法,用正则表达式匹配卡号。

# 匹配主流卡BIN范围(仅示例,实际更复杂)
^4\d{12,18}$             # Visa
^5[1-5]\d{14}$           # Mastercard
^3[47]\d{13}$            # AmEx
^6(?:011|5\d{2})\d{12}$ # Discover

但光靠正则不行。我踩过坑:一个订单号是 4000001234567890,刚好符合Visa的格式,被系统误识别为PAN,直接触发了告警。

2.3.2 Luhn算法校验

真正的PAN,必须通过Luhn算法校验。这是卡组织定的规矩。

func LuhnCheck(cardNumber string) bool {
    var sum int
    alternate := false
    for i := len(cardNumber) - 1; i >= 0; i-- {
        n := int(cardNumber[i] - '0')
        if alternate {
            n *= 2
            if n > 9 {
                n = n%10 + 1
            }
        }
        sum += n
        alternate = !alternate
    }
    return sum%10 == 0
}
经验: 我在项目中总是“正则 + Luhn + 上下文规则”三层过滤。比如,字段名包含“card_no”、“pan”、“account_number”这些关键词时,才触发深度校验。误报率从70%降到了5%以下。

2.4 核心结构图:从输入到分类

下面这张图,展示了一个支付字段从进入系统到完成分类的完整流程。我把它当作数据识别的“标准操作流程”。

支付字段数据识别与分类流程 原始支付字段 步骤1:正则BIN匹配 步骤2:Luhn算法校验 是否通过? L4 - 非敏感 触发分类引擎 L1 - 极高 L2 - 高 L3 - 中 关键判断逻辑 1. 正则 + Luhn 双重过滤 2. 上下文字段名辅助判断
这张图的核心逻辑很简单:所有输入字段先过“正则+Luhn”双重过滤。没通过的,直接判为L4非敏感。通过的,进入分类引擎,再根据上下文(有效期、CVV)细分为L1、L2、L3。

2.5 实践中容易出的问题

说几个我亲历的痛点。

2.5.1 误把令牌当PAN

令牌和PAN都是16-19位数字。我第一次做令牌服务时,日志里抓到一个“PAN”告警,查了半天才发现是令牌桶里的值。后来我加了一条规则:如果字段来源是令牌服务接口,直接跳过Luhn校验。

2.5.2 有效期误判

“12/28”这种格式,很容易被正则误认为一个路径或时间戳。我建议把有效期识别限定在“紧随PAN号出现”或“字段名为exp_date/expiry”的上下文里。

2.5.3 忽略磁道数据

磁道数据里嵌了PAN。有些系统只识别了显性卡号字段,却把磁道数据当普通字符串存储。这其实是L1级别的风险。我在网关层专门加了一个解析器,碰到 %B 开头的字符串,自动触发PAN提取和分类。

2.6 本章小结

做好PAN数据识别,是整个令牌服务设计的地基。

记几个关键点:

  • 定义清楚L1-L4的四级分类标准,让团队有据可依。
  • 用“正则+Luhn+上下文”三重过滤,减少误报。
  • 别忘了磁道数据、有效期这类“隐形”敏感字段。

把这些搞明白了,下一步才能放心讨论“令牌的生成与生命周期管理”。