最近在整理一批和美国身份信息有关的逻辑,顺手又把 [[SSN]] 这件事重新捋了一遍。很多没有在美国长期生活过的人,第一次看到 SSN,往往会把它当成一个普通编号。真到了网上申请 [[信用卡]]、开银行账户、补税务资料、查征信报告这些场景,才会发现这 9 位数字几乎绕不过去。它不是那种只印在卡面上、平时想不起来的号码,而是会反复出现在各种线上流程里。
我后来才慢慢意识到,SSN 在美国很多系统里其实就是那根暗线。你在网页上填完姓名、生日、住址、收入和 SSN,后面可能立刻就接上征信查询、身份匹配、地址历史核验和反欺诈检查。银行、券商、雇主、税务机构、保险公司、房东、电信公司,几乎每家都有自己的用法。这篇文章就把几件最容易混在一起的事情分开讲清楚:SSN 是什么,为什么它这么重要,9 位数字怎么拆,哪些范围天然无效,2011 年 6 月 25 日之后规则改了什么,以及所谓“SSN 校验”到底能做到哪一步。
SSN 到底是什么
SSN,全称是 Social Security Number,由 [[Social Security Administration]] 发放。它最早不是为了做一个“万能身份证号”,而是为了把个人的社会保障记录、收入记录和未来福利对应起来。后来工资发放、税务申报、银行开户、征信、背景调查这些流程越来越依赖数字系统,SSN 也就一点点变成了最常见的个人识别字段之一。
但有一点要先说清楚:SSN 很重要,不等于“只要有 SSN,身份就算验过了”。SSA 自己提供的验证服务也说明了这一点。真正的核验不是只看这 9 位数字,而是把姓名、出生日期、SSN 这些信息放在一起做比对。换句话说,本地写一个正则表达式,做的只是格式检查,不是身份认证。
为什么 SSN 在美国这么重要
把美国常见的线上服务拆开看,SSN 的作用远不只是“填一个身份字段”。一个很典型的例子就是在线申请 [[信用卡]]。用户在网站上填完姓名、生日、住址、收入和 SSN,发卡行后面很快就会接征信查询、身份匹配、反洗钱检查和反欺诈风控。SSN 填错了,或者姓名和 SSN 对不上,很多申请会直接进人工审核,有些当场就会被拒。
类似的逻辑也出现在很多别的流程里。开美国银行账户、券商账户、报税、入职背景调查、申请某些政府福利、租房、开通手机套餐,甚至只是去看自己的信用报告,背后都可能要用到 SSN。对美国本地系统来说,它常常就是把征信档案、工资记录、税务记录和历史身份信息串起来的那个字段。也正因为这样,SSN 一方面很好用,另一方面也非常敏感。一旦泄露,麻烦往往不是“号码被别人看到了”,而是别人可能拿它去拼你的整套身份材料。
SSN 的结构和有效范围
传统写法里,SSN 通常会显示成 AAA-GG-SSSS。虽然实际存储时很多系统会去掉中间的连字符,只保留 9 位数字,但拆开来看更容易理解。
| 部分 | 位数 | 基本规则 |
|---|---|---|
| Area | 前 3 位 | 不能是 000、666,也不能落在 900-999 |
| Group | 中间 2 位 | 不能是 00 |
| Serial | 后 4 位 | 不能是 0000 |
换句话说,如果只从“范围”来判断,一个可能合法的 SSN 必须满足下面这些条件:
- 总长度是 9 位数字
- 前 3 位在
001-665或667-899之间 - 中间 2 位在
01-99之间 - 后 4 位在
0001-9999之间
这几个规则里最容易被忽略的一点,是前导零不能丢。比如 001 这种 area number 在格式上是可能存在的,所以无论你用什么语言处理 SSN,都应该把它当成字符串,而不是整数。只要一转成数值类型,前导零就没了,后面的校验和展示都会跟着出问题。
2011 年之后,号段的含义变了
如果你去翻一些老资料,会看到前 3 位 area number 以前带有明显的地理含义,不同州对应不同区段;中间 2 位 group number 也有自己的发放顺序。这些资料不算错,只是有时效性,它们说的是旧时代的分配逻辑。
[[Social Security Administration]] 在 2011 年 6 月 25 日启用了 SSN randomization。这个变化有三个直接后果:
- 前 3 位不再用来表示州别或申请地
- 过去拿来推断号码是否可能存在的 High Group List 不再更新
- 系统开始以随机化方式分配更多可用号段,但仍然保留
000、666、900-999这些禁用范围
所以今天再看到一个 SSN,尤其是 2011 年 6 月 25 日之后首次签发的号码,已经不能再像旧资料那样,靠前 3 位去猜它来自哪个州,也不能继续拿 high group 的老表去判断“这个号绝对不可能存在”。很多旧的“SSN 查询网站”或“号段反查工具”问题就出在这里,看起来头头是道,底下用的却是过期规则。
所谓 SSN 校验,究竟能做什么
这里最容易让人误会。SSN 没有像银行卡号那样公开可用的 checksum,也没有一个你离线套个公式就能判断真假的校验位。公开规则能告诉我们的,只有格式层面的限制,也就是长度、是否全数字、禁用号段、禁用 group 和禁用 serial。
说白了,任何脱离 SSA 官方记录的“本地 SSN 校验”,最多只能回答下面这个问题:
这个输入,看起来像不像一个可能被分配出去的 SSN?
它不能回答下面这些更关键的问题:
- 这个 SSN 是否真实签发过
- 这个 SSN 是否和某个姓名匹配
- 这个 SSN 是否和某个出生日期匹配
- 这个号码对应的人是否仍然存活
- 这个人是否具有某种特定资格
SSA 自己给出的方向也很清楚。真到了业务场景,应该走它提供的验证服务,不要迷信本地号段推断。比如雇主可以使用 [[SSNVS]],某些经过许可的机构可以通过 CBSV 或 eCBSV,在取得当事人同意后,核对姓名、出生日期和 SSN 是否与 SSA 记录一致。SSA 在 CBSV 页面上也写得很直白:它返回的是匹配或不匹配的结果,必要时还会返回死亡标记,但这依然不等于“这个人的身份已经彻底验证完毕”。
一个可落地的格式检查思路
如果你的目标只是写表单校验、数据清洗,或者给批量导入做预处理,我一般会把 SSN 检查分成四步,而不是只丢一个正则过去就算结束:
- 先把空格和连字符去掉,统一成 9 位纯数字字符串
- 检查长度是否等于 9,并确认全部字符都是数字
- 检查 area、group、serial 是否命中禁用范围
- 把结果命名为“possible”或“format-valid”,不要命名成“verified”
一个够用的正则可以写成这样:
^(?!000|666|9\d\d)\d{3}[-]?(?!00)\d{2}[-]?(?!0000)\d{4}$
如果想把逻辑写得更直白一点,我更推荐代码里显式拆段,而不是把所有规则都塞到同一个正则里。比如用 JavaScript,可以写成下面这样:
function isPossibleSSN(input) {const normalized = input.replace(/[-\s]/g, "");
if (!/^\d{9}$/.test(normalized)) return false;
const area = normalized.slice(0, 3);
const group = normalized.slice(3, 5);
const serial = normalized.slice(5, 9);
if (area === "000" || area === "666") return false;
if (Number(area) >= 900) return false;
if (group === "00") return false;
if (serial === "0000") return false;
return true;
}
这段逻辑的价值不在“查真伪”,而在于尽早过滤那些明显不对的数据,比如用户随手乱填的 123-00-4567、000-12-3456,或者长度不对的输入。对于注册表单、CRM 导入、KYC 前置清洗,这一步很有用;但如果把它包装成“SSN 验证通过”,那就说过头了。
实际使用时的几个建议
我自己在设计这类字段时,会额外盯几件事情。不要把完整 SSN 当普通字符串到处打进日志,更不要在前端报错里原样回显。如果业务只需要识别记录,优先只展示最后四位,尽量少暴露敏感信息。真有合规级别的核验需求,就从一开始把流程设计成“格式检查 + 官方验证服务”,别等系统上线之后才发现正则根本不够用。
还有一个很常见的坑,就是把老时代的 area number 对照表继续用在今天的新数据上。历史资料当然有价值,特别是在清洗老存量数据的时候,它能帮你理解过去的分配逻辑。但只要数据里混进了 2011 年 6 月 25 日之后分配的新 SSN,继续按州别或 high group 规则去推断,就很容易误杀。
常见误区
围绕 SSN,最常见的误区大概就这几个。
- “首三位可以直接判断州别。”这只适用于 2011 年 6 月 25 日之前的旧分配逻辑,对现代 SSN 不成立。
- “SSN 一定有校验位。”没有公开可用的 checksum,可以做的只是格式合法性检查。
- “正则通过就说明这个 SSN 真实存在。”不成立,正则只能说明输入看起来像一个可能合法的号码。
- “只要知道一个人的 SSN,就等于身份已经确认。”也不成立,真实核验仍然需要结合姓名、出生日期甚至业务场景里的额外证明材料。
和中国身份证号、日本 My Number 放在一起看
如果只盯着 SSN 自己看,很多人还是会有点模糊。把它和中国身份证号、日本的 My Number 放在一起,差别就会清楚很多。三者都能和“个人身份”扯上关系,但制度定位其实差得很远。
中国身份证号是三者里结构信息最直白的一个。18 位号码里,前 6 位是行政区划代码,中间 8 位是出生日期,接着 3 位是顺序码,最后 1 位是校验码,校验结果可能是数字,也可能是 X。这意味着中国身份证号天生就带着比较多的个人属性信息,本地也能做更强的结构校验:你不但可以检查长度和字符集,还能检查生日是否合法、校验位对不对。可就算这些都通过了,它依然只能说明“这个号码在结构上成立”,不等于站在你面前的人就一定是号码对应的本人。
日本的 My Number 走的是另一条路。官方定位非常明确,它是给住民票上的每个人分配的 12 位个人番号,主要用于社会保障、税和灾害对策这几类行政事务。从官方宣传材料看,它的重点一直不是“让所有民间场景都把这个号码拿来当万能钥匙”,而是把行政联通的范围控制在明确的法定用途里。官方材料甚至专门提醒,除了税务等法定手续外,随意告诉别人自己的 My Number,或者在没有正当事由的情况下索要、收集、保管别人的 My Number,都是不被允许的。
如果再看卡片设计,这个差别会更明显。中国身份证本身就是最核心的法定身份证件之一,号码和证件是一起使用的。日本则是把“个人番号”与“卡片能力”区分开来:My Number Card 可以拿来做线下和线上身份确认,但官方同时强调,卡片 IC 芯片里只存放电子证明书等最小必要信息,并不直接把税、年金、存款这些隐私数据塞进去。换句话说,日本制度更强调“编号的使用边界”和“卡片的认证能力”是两件事。
这样一对比,我自己会把三者粗略理解成下面这个样子。
- 美国 SSN 更像一个被金融、雇佣、征信体系广泛复用的关联号码。它非常重要,但本地能做的格式校验其实最弱。
- 中国身份证号是结构信息最丰富的号码,生日、地区、校验位都直接写在号码里,所以本地可校验性最强,但也因此暴露的信息更多。
- 日本 My Number 的法定使用边界最清楚。它也重要,但制度上更强调只在社会保障、税和灾害对策这些场景里使用,不鼓励在民间流程里到处流转。
所以如果把问题拉回到文章开头提到的“网上申请信用卡”这个场景,美国 SSN 的感觉最特别。它在很多商业流程里已经成了默认字段,很多网站一上来就让你填。中国更常见的是身份证号和实名信息、银行卡、人脸核验一起使用。日本的 My Number 从官方用途范围来看,则明显更偏行政和税务体系,不是一个为了日常消费金融场景而设计出来的“通用号码”。
最后
如果只记住一句话,那就是:SSN 可以做格式检查,但不能靠本地算法做真实核验。前者解决的是输入质量,后者解决的是身份匹配。名字看着有点像,实际上不是一回事。
所以无论是写代码、做数据治理,还是给运营同学解释规则,我都建议一开始就把字段状态拆成两层:一种叫 format-valid 或 possible,表示这个号码在结构上说得通;另一种叫 verified,表示它已经通过官方或合规渠道完成核对。前面这一步解决的是“格式像不像”,后面这一步解决的是“人是不是这个人”。两件事分清楚,后面的系统设计、权限控制和审计记录都会轻松很多。
参考资料
- SSA Number & Card: https://www.ssa.gov/number-card
- SSA SSN Randomization FAQ: https://www.ssa.gov/employer/randomizationfaqs.html
- SSA POMS RM 10201.045: https://secure.ssa.gov/poms.nsf/lnx/0110201045
- SSA Historical Order of Issuance: https://www.ssa.gov/employer/ssnweb.htm
- SSA SSNVS Handbook: https://www.ssa.gov/employer/ssnvshandbk/usingSSNVS.htm
- SSA CBSV: https://www.ssa.gov/cbsv/
- 北京市公安局关于公民身份号码结构与校验码的说明: https://gaj.beijing.gov.cn/hudong/rddf/202003/t20200331_1771804.html
- 日本政府 My Number 说明资料: https://www.kojinbango-card.go.jp/mynumber/
- 日本政府 My Number 安全性说明: https://www.kojinbango-card.go.jp/en-kojinbango-security/