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

Posted 白夜鸦羽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[安全开发]日志敏感信息检测-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\\d6(19|20)\\d2((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d3[0-9Xx]\\W

正则说明

  • \\W:匹配非单词字符,与"[^A-Za-z0-9_]"等效
  • \\d6:匹配前6位地址码
  • (19|20)\\d2:匹配年份
  • ((0[1-9])|(10|11|12)):匹配月份
  • ((\\[0-2][1-9])|10|20|30|31):匹配日期
  • \\d3:匹配顺序码
  • [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-身份证的主要内容,如果未能解决你的问题,请参考以下文章

[安全开发]日志敏感信息检测-3-正则合集(手机号邮箱车牌号)

常见开发场景安全开发指南

网络安全学习笔记工具篇——GSIL GITHUB敏感信息泄露检测工具

[安全开发]敏感信息脱敏函数

java 日志脱敏框架 sensitive,优雅的打印脱敏日志

java 日志脱敏框架 sensitive,优雅的打印脱敏日志