才知道身份证不是随便更改一位就可以使用的!!!
最近开发后台的用户模块,碰到个挺有意思的事儿 —— 用 validator 库校验身份证的时候,我用网上的身份证生成器弄了个虚拟号码,填进去一下子就通过了;结果我闲得慌,想试试改一位数字会怎么样,不管改的是前面的地址码,还是最后一位,提交之后立马就报 “格式无效”。
最开始我还以为是自己配置 validator 的时候漏了什么,翻来覆去查校验规则,确认没写错啊!后来琢磨了半天才反应过来:原来身份证号根本不是随便凑的字符串,里面藏着一套严格的编码逻辑,别说改一位了,改半个字符都能让整个校验垮掉。
18 位身份证的结构是什么?
咱们常用的第二代身份证是 18 位,看着一串数字挺乱,但每一段都有讲究,大概能分成四部分:前 6 位是地址码,代表你户籍所在的省市区,比如 110101 就是北京东城区;中间 8 位是出生日期,这个好认,就是 YYYYMMDD 的格式,比如 19900101 就是 1990 年 1 月 1 日;接下来 3 位是顺序码,同一个地方同一天出生的人,就靠这三位区分,而且奇数是男的,偶数是女的;最后 1 位最关键,叫校验码,是根据前面 17 位算出来的 —— 我这次踩坑,问题就出在这儿。
校验码是怎么算出来的?
validator 校验身份证的时候,不只是看前 17 位格式对不对,更重要的是检查最后一位校验码和前面的数字能不能对上。这个计算方法是固定的,叫 ISO 7064:1983.MOD 11-2 算法,说起来复杂,其实步骤很明确,我拿个例子给你们拆拆看。
比如前 17 位是 11010119900101123,算校验码得这么来:首先给前 17 位分配一组固定的权重,具体是 [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2],不用记,知道有这么一组数就行;然后把每一位数字和对应的权重相乘,再把所有结果加起来,我算出来是 137;接着用 137 除以 11,余数是 5;最后看余数找对应的校验码 —— 官方有个对应表,余数 5 对应的是 7,所以完整的身份证号就是 110101199001011237。
这么一说,我之前的问题就很明显了。那些身份证生成器生成的号码,都是按照这套规则来的:先凑齐符合格式的前 17 位,再算出对应的校验码,所以能轻松通过 validator。但我手动改数字的时候,不管改的是哪一位,都会打破这种对应关系 —— 改前 17 位的话,前面的总和变了,校验码自然就对不上;直接改最后一位校验码更简单,它本来就是算出来的,一改肯定不匹配。validator 一检查这两项,发现对不上,就直接返回失败了。
总结
这次踩坑给我的感触还挺深的,原来像身份证号、银行卡号这种看似普通的编码,背后都有成熟的校验逻辑。以后开发碰到类似问题,真别先急着怀疑自己的代码配置,不如先去查查底层原理 —— 奇怪的知识就增加了