最近有媒体爆出12306可以用假的身份证号码在12306.cn上买票的新闻。所以对12306.cn如何验证身份证号码真伪产生了兴趣。
怎么验证呢,当然离不开chrome大婶和火狐妹子了,
首先修改下个人信息,随便打上一个身份证号码,基本上你打的一定是不对的,所以他会提示你:“请正确输入18位的身份证号!”
我们来找下这个提示从哪里来的呢?
我找啊找,找到了“formCheck.js”,而且没有被压缩,可视性不错,
在这里边,我发现 了这么一段
function validateSecIdCard(value){ var iSum = 0; var sId= value; var aCity = { 11 : "北京", 12 : "天津", 13 : "河北", 14 : "山西", 15 : "内蒙", 21 : "辽宁", 22 : "吉林", 23 : "黑龙", 31 : "上海", 32 : "江苏", 33 : "浙江", 34 : "安徽", 35 : "福建", 36 : "江西", 37 : "山东", 41 : "河南", 42 : "湖北", 43 : "湖南", 44 : "广东", 45 : "广西", 46 : "海南", 50 : "重庆", 51 : "四川", 52 : "贵州", 53 : "云南", 54 : "西藏", 61 : "陕西", 62 : "甘肃", 63 : "青海", 64 : "宁夏", 65 : "新疆", 71 : "台湾", 81 : "香港", 82 : "澳门", 91 : "国外" }; if (!/^d{17}(d|x)$/i.test(sId)) { return false; } sId = sId.replace(/x$/i, "a"); //非法地区 if (aCity[parseInt(sId.substr(0, 2))] == null) { return false; } var sBirthday = sId.substr(6, 4) + "-" + Number(sId.substr(10, 2)) + "-" + Number(sId.substr(12, 2)); var d = new Date(sBirthday.replace(/-/g, "/")); //非法生日 if (sBirthday != (d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d .getDate())) { return false; } for ( var i = 17; i >= 0; i--) { iSum += (Math.pow(2, i) % 11) * parseInt(sId.charAt(17 - i), 11); } if (iSum % 11 != 1) { return false; } return true; } function validateFirIdCard(value){ var iSum = 0; var sId; var aCity = { 11 : "北京", 12 : "天津", 13 : "河北", 14 : "山西", 15 : "内蒙", 21 : "辽宁", 22 : "吉林", 23 : "黑龙", 31 : "上海", 32 : "江苏", 33 : "浙江", 34 : "安徽", 35 : "福建", 36 : "江西", 37 : "山东", 41 : "河南", 42 : "湖北", 43 : "湖南", 44 : "广东", 45 : "广西", 46 : "海南", 50 : "重庆", 51 : "四川", 52 : "贵州", 53 : "云南", 54 : "西藏", 61 : "陕西", 62 : "甘肃", 63 : "青海", 64 : "宁夏", 65 : "新疆", 71 : "台湾", 81 : "香港", 82 : "澳门", 91 : "国外" }; //如果输入的为15位数字,则先转换为18位身份证号 if (value.length == 15) sId = idCardUpdate(value); else sId = value; if (!/^d{17}(d|x)$/i.test(sId)) { return false; } sId = sId.replace(/x$/i, "a"); //非法地区 if (aCity[parseInt(sId.substr(0, 2))] == null) { return false; } var sBirthday = sId.substr(6, 4) + "-" + Number(sId.substr(10, 2)) + "-" + Number(sId.substr(12, 2)); var d = new Date(sBirthday.replace(/-/g, "/")); //非法生日 if (sBirthday != (d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d .getDate())) { return false; } for ( var i = 17; i >= 0; i--) { iSum += (Math.pow(2, i) % 11) * parseInt(sId.charAt(17 - i), 11); } if (iSum % 11 != 1) { return false; } return true; } function idCardUpdate(_str) { var idCard18; var regIDCard15 = /^(d){15}$/; if (regIDCard15.test(_str)) { var nTemp = 0; var ArrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2); var ArrCh = new Array(’1’, ’0’, ’X’, ’9’, ’8’, ’7’, ’6’, ’5’, ’4’, ’3’, ’2’); _str = _str.substr(0, 6) + ’1’ + ’9’ + _str.substr(6, _str.length - 6); for ( var i = 0; i < _str.length; i++) { nTemp += parseInt(_str.substr(i, 1)) * ArrInt[i]; } _str += ArrCh[nTemp % 11]; idCard18 = _str; } else { idCard18 = "#"; } return idCard18; }
不知道有没有注意前两段是检查了相应的城市、生日等信息。那么最后一段是干什么的呢?
这我们需要从身份证号的构成来分析了。
<中华人民共和国国家标准GB 11643-1999《公民身份号码》中规定:公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。
18位数字组合的方式是:
1 | 1 | 0 | 1 | 0 | 2 | Y | Y | Y | Y | M | M | D | D | 8 | 8 | 8 | X |
地址码 | 出生日期码 | 顺序码 | 校验码 |
这样,就出现了黄牛使用网上的一些身份证号码生成器就能生成符合条件的身份证号码从而注册大量的号码来刷票。 面对这种情况,通过本地的相关算法来判断身份证号码是否合法似乎已经无法解决。但是如果使用公安部提供的身份证信息查询的服务似乎也是不太靠谱,毕竟能github都能被拖垮,公安部的那家事业单位的服务器很难顶的住啊……万一出问题,问题就可就大了。