Python身份证脱敏案例:如何隐藏证件号?超详细操作指南
📚 目录导读
为什么要做身份证脱敏?
在数据处理、日志输出、接口返回等场景中,身份证号属于敏感个人信息,根据《个人信息保护法》,企业必须对敏感数据进行脱敏处理,否则可能面临法律风险。

核心需求:将完整的18位身份证号码(如110101199001011234)转换成保留部分信息的模糊形式(如110101******1234),既满足业务需要,又能保护用户隐私。
常见的身份证脱敏规则
| 规则类型 | 脱敏方式 | 示例 |
|---|---|---|
| 保留前6后4 | 显示前6位(地址码)+ 后4位(顺序码校验码),中间8位隐藏 | 110101 ****** 1234 |
| 保留前6后3 | 显示前6位+后3位,中间9位隐藏 | 110101 ********* 234 |
| 保留前2后2 | 只显示前2位省份码+后2位,中间14位隐藏 | 11**** **** **** 34 |
| 全部隐藏 | 完全不显示身份证号 |
业务推荐:大多数场景使用保留前6后4规则,因为前6位可以区分地区,后4位用于确认用户身份,中间8位(出生日期+顺序码)严格隐藏。
Python实现身份证脱敏的5种方案
这里整理了5种从简单到复杂的实现方式,你可以根据项目场景选择。
方案1:字符串切片替换(最基础)
def mask_id_card_v1(id_card):
return id_card[:6] + "********" + id_card[-4:]
方案2:正则表达式替换
import re
def mask_id_card_v2(id_card):
return re.sub(r'(?<=\d{6})\d{8}(?=\d{4})', '********', id_card)
方案3:使用format格式化
def mask_id_card_v3(id_card):
return "{}********{}".format(id_card[:6], id_card[-4:])
方案4:支持自定义脱敏长度
def mask_id_card_v4(id_card, front=6, end=4, mask_char='*'):
mask_len = len(id_card) - front - end
return id_card[:front] + mask_char * mask_len + id_card[-end:]
方案5:批量脱敏(pandas适用)
import pandas as pd
def mask_id_card_v5(df, column_name):
df[column_name] = df[column_name].apply(lambda x: x[:6] + '********' + x[-4:])
return df
完整代码实战案例
下面是一个完整的Python脚本示例,包含数据生成、脱敏、验证和导出功能。
import pandas as pd
import random
import re
# 1. 生成模拟身份证数据
def generate_fake_id_card():
"""生成一个假的身份证号(仅用于演示)"""
area_code = "110101"
birth = "19900101"
seq = str(random.randint(100, 999))
# 校验码简单生成(正式校验需ISO 7064:1983)
check = "X" if random.random() > 0.9 else str(random.randint(0, 9))
return area_code + birth + seq + check
# 2. 脱敏函数(推荐方案)
def mask_id_card(id_card):
"""仅保留前6位和后4位,中间用*替换"""
if len(id_card) != 18:
return id_card # 非18位不处理
return id_card[:6] + "********" + id_card[-4:]
# 3. 批量处理+导出
data = {
"user_id": [1, 2, 3, 4, 5],
"name": ["张三", "李四", "王五", "赵六", "钱七"],
"id_card": [generate_fake_id_card() for _ in range(5)]
}
df = pd.DataFrame(data)
# 应用脱敏
df["id_card_masked"] = df["id_card"].apply(mask_id_card)
print("原始数据:")
print(df[["name", "id_card"]])
print("\n脱敏后的数据:")
print(df[["name", "id_card_masked"]])
# 4. 导出为CSV
df.to_csv("masked_data.csv", index=False, encoding="utf-8-sig")
输出示例: | name | id_card_masked | |------|----------------| | 张三 | 1101011234 | | 李四 | 1101015678 |
脱敏后的数据验证与注意事项
✅ 验证要点
- 长度校验:脱敏后字符串长度必须与原身份证号一致(18位)
- 格式保留:前6位和后4位必须是数字,中间8位是
- 可逆性:脱敏数据应不可逆,不能通过算法恢复原始数据
⚠️ 注意事项
- 国际化公民号:如果处理港澳台、外籍人士证件,长度和格式不同,需单独处理
- 日志脱敏:在打印日志时,建议使用
logging模块配合自定义Filter实现自动脱敏 - 数据库层面:可以使用MySQL的
INSERT()函数或SQL Server的STUFF()函数在查询时脱敏
Q&A常见问题
Q1:脱敏后的身份证还能查到具体出生日期吗?
答:不能,采用保留前6后4规则后,隐藏的是第7-14位(出生日期),用户无法从脱敏数据推断具体生日。
Q2:为什么不用替换整个字符串?
答:保留前6位可以区分地区,后4位用于数据比对(如确认该用户是否存在),全隐藏会导致业务无法正常使用。
Q3:如果身份证号是15位(旧版)怎么办?
答:可在代码增加分支判断:
if len(id_card) == 15:
return id_card[:6] + "*****" + id_card[-4:]
elif len(id_card) == 18:
return id_card[:6] + "********" + id_card[-4:]
Q4:脱敏后还能用于匹配数据库吗?
答:建议在数据库层保存原始加密数据(如AES加密),对外接口返回脱敏数据,业务匹配应通过加密后的hash值进行,而非脱敏字符串。
Q5:有没有一键脱敏的Python库推荐?
答:推荐使用presidio-anonymizer(微软开源)或faker(生成脱敏数据),但若只需简单规则,自己写函数更轻量。
身份证脱敏是数据安全的必备技能,在Python中,通过字符串切片结合替换是最常用且可靠的方法,建议始终保留前6位和后4位,其他位置隐藏,以保证业务可识别性,如果需要进一步处理大量数据,可以结合pandas进行批量操作。