[安全开发]日志敏感信息检测-1-身份证

  1. 前言
  2. 身份证号码格式
  3. 正则提取
  4. 地址码校验
  5. 校验码校验
  6. 优化思考

前言

防止敏感信息泄漏,保护用户和企业信息隐私,是企业安全中重要的环节。

通过检测日志中的敏感信息,能够:

  1. 排查潜在的泄漏敏感信息的系统和接口,防止被黑产恶意利用,盗取用户敏感信息
  2. 检查数据传输、日志打印的规范,是否对敏感信息有做加密、脱敏等处理

对于海量日志的敏感信息检测,可以采用Flink流数据处理引擎,进行检测排查。

本文不讨论Flink,只记录日志中身份证号码检测规则的一点心得。

身份证号码格式

一代身份证基本不存在了,无需做检测,一起来看看二代身份证的格式。

二代身份证号码共18位,由17位本体码和1位校验码组成:

  • 前6位:地址码,表示登记户口时所在地的行政区划代码
  • 7到14位:出生年月日,采用YYYYMMDD格式
  • 15到17位:顺序码,同一地区,同一年月日出生的人的顺序编号,男生奇数,女生偶数
  • 第18位:校验码,由前17位本体码计算得到

补充说明一下,二代身份证与一代身份证的区别:

  • 位数:一代身15位,二代18位
  • 出生日期:一代为YYMMDD格式,二代为YYYYMMDD格式
  • 校验码:一代无校验码,二代有校验码

正则提取

首先通过正则,进行简单的筛选,从日志中提取疑似身份证号码的数字。

\W\d{6}(19|20)\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]\W

正则说明

  • \W:匹配非单词字符,与"[^A-Za-z0-9_]"等效
  • \d{6}:匹配前6位地址码
  • (19|20)\d{2}:匹配年份
  • ((0[1-9])|(10|11|12)):匹配月份
  • ((\[0-2][1-9])|10|20|30|31):匹配日期
  • \d{3}:匹配顺序码
  • [0-9Xx]:匹配校验码

从生产实践的经验来看,日志中大部分变量值,都被符号所包围,例如:

  • example?name=shadow&phone=12345678910&……
  • “id_card”:“110101199003071938”,“age”:“18”……

而未被符号所包围的变量,绝大部分可能都是误报,例如:

  • deptNo=17261101011990030719384324

所以,初期做日志的敏感信息检测时,可以从这些特殊符号入手,用正则\W去做匹配,这样能提高不少准确率。后期敏感信息都被揪出来之后,再去掉\W,去进行更大范围、更进一步的检测排查。

在上面的正则表达式里,我们对身份证年月日的部分做了简单校验,但我们不能据此就判定,检测出的是身份证号码,因为在海量日志里,正则会匹配到各种巧合的误报。而依靠人工去筛查这些误报,确认风险,是很费时费力的。我们要做的,就是继续要提高身份证号检测的准确率,所以接下来,我们进一步对身份证号的地址码和校验码进行校验。

地址码校验

身份证的前6位地址码是固定的,我们可以取这前6位数字,与地址码库进行匹配,若匹配成功,则进行下一步,校验码的校验。
地址码库搬运:身份证号码前6位地址码
地址码样例

校验码校验

前面说了,身份证最后一位是校验码,由前17位本体码计算得到,具体的计算算法这里不深究,感兴趣的读者,可以参考这篇博客:身份证号码的编码规则及校验
这里我们直接给出,身份证号码校验码的校验算法的Java代码实现:

/**
 *
 * 18位的二代身份证号码校验码校验
 * @param idCardNo 身份证号码
 * @return true - 校验通过
 *         false - 校验不通过
 */
private static boolean idCardNoCheck(String idCardNo) {
    // 加权因子
    int[] w = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
    char[] idCardNoArray = idCardNo.toCharArray();
    int sum = 0;
    for (int i = 0; i < w.length; i++) {
        sum += Integer.parseInt(String.valueOf(idCardNoArray[i])) * w[i];
    }
    // 校验位是X,则表示10
    if (idCardNoArray[17] == 'X' || idCardNoArray[17] == 'x') {
        sum += 10;
    } else {
        sum += Integer.parseInt(String.valueOf(idCardNoArray[17]));
    }
    // 如果除11模1,则校验通过
    return sum % 11 == 1;
}

优化思考

通过上面的 正则提取+地址码校验+校验码校验 三部曲,从日志中检测出的数字,基本99%是身份证号码,准确率极高。但在海量日志的检测过程中,各种奇葩数据都有,还是会存在1%的误报的。

对于这1%的误报,有两个处理思路:

  1. 误报为偶然出现,且只出现过一两次,也没有其他类似特征的误报,则直接忽略即可
  2. 误报具有一定的特征,且多次出现,为同一类误报,则可以提取特征,针对性的制定白名单过滤。白名单推荐采用正则匹配进行过滤
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值