简介:《C0131国家政务服务平台统一身份认证隐私保护要求》面向政务服务平台建设方、统一身份认证系统开发者及隐私合规人员,梳理身份认证场景下个人信息保护的标准依据与落地要点。资源包仅含1个PDF文件,大小约188KB,便于直接查阅与归档。内容围绕隐私数据定级、判定、使用与责任展开,明确一级至三级数据的保护差异,并覆盖收集、保存、加工、共享披露、导出输出、归档销毁等环节的基本原则和操作边界;同时列出网络安全法、个人信息安全规范等引用依据,以及组织管理与检查检测要求,附录A还给出自然人身份信息隐私判定说明。已有820人学习,可用于政务身份认证项目的合规自查、制度编写和隐私影响评估参考。
1. 统一身份认证的隐私边界:27 项字段定级表能挡掉多少返工
政务服务平台统一身份认证隐私保护这件事,多数人是被整改单推着入场的:系统跑了大半年,一纸检查意见下来,说身份认证节点字段分级不清、日志存得不够、脱敏比例不达标。翻遍手里的开发文档,找不到一条能直接抄的规则,全是“应按相关要求执行”。C 0131-2018 补的就是这个缺口——它把统一身份认证里哪些字段算隐私、算几级、怎么存、怎么显示、谁能碰,写成了可对照的条款,还附了一张 27 项自然人身份信息的判定表。它不教你写代码,但给了你一把能贴在工位上的尺子。正在做政务身份认证对接、被合规改造追着跑,或者要给团队定字段分级基线的人,值得把它当底稿读一遍。
2. 三级定级落地:把附录 A 的 27 项字段拆成数据字典
2.1 定级不看“感觉敏感”,先看能不能落到自然人身上
标准给的三级划分有一条主线:能不能对应到自然人实体。一级数据是“不能对应到自然人实体身份信息的数据”,证件类型、实名等级、性别、民族、国籍这些都归一级;二级是“可用于标识自然人实体的身份信息,且较公开”,登录账号、姓名、手机号是典型;三级是“可用于标识自然人实体,且具有较高隐私性”,证件编号、户籍地址、居住地址在列。
这条主线的好处是它可判定。团队评审时最常吵的是“这个字段敏不敏感”,这种争论没有收敛点。换成“这个字段单独出现时能不能定位到某一个人”,讨论立刻落地。证件类型不能,证件编号能,所以一个一级一个三级。性别不能,姓名加手机号能,所以姓名和手机号都是二级。我一般要求评审时把每个字段填进一句话模板:“持有该字段值的人,能否在系统内唯一定位一个自然人”,答能就至少二级,答不能才考虑一级。
真正容易翻车的是“单字段级别低、组合起来级别高”的情况。标准本身按字段定级,但 6.5 条另外禁止了以两个或两个以上用户的个人信息做关联分析,也禁止跨用户以散列值做关联。也就是说字段级定级是底线,不是全部;字段组合后的可识别性要在数据加工环节另行受约束。把定级表当唯一答案,会漏掉组合场景。
2.2 附录 A 的 27 项字段,按级别拆成三张落地表
附录 A 是规范性附录,它才是实施时的准绳。我习惯把它直接翻成三张表,每张表带一列“实施动作”,让开发和运维看到级别就知道该干什么,而不是回头再查一遍正文。
一级数据(8 项),存储无特殊要求,但仍受通用安全要求约束:
| 字段 | 级别 | 实施动作 |
|---|---|---|
| 自然人证件类型 | 一级 | 可明文;导出仍需登记 |
| 证件散列码 | 一级 | 可明文;禁止用于跨用户关联分析 |
| 自然人实名等级 | 一级 | 可明文 |
| 自然人实名核验日期 | 一级 | 可明文 |
| 用户性别 | 一级 | 可明文 |
| 用户类型 | 一级 | 可明文 |
| 用户民族 | 一级 | 可明文 |
| 用户国籍 | 一级 | 可明文 |
三级数据(4 项),互联网区必须不可逆处理,外网必须加密:
| 字段 | 级别 | 实施动作 |
|---|---|---|
| 自然人证件编号 | 三级 | 互联网区散列存储,禁止明文与可逆加密 |
| 社保卡号 | 三级 | 同上 |
| 用户户籍地址 | 三级 | 同上;显示按地址规则脱敏 |
| 用户居住地址 | 三级 | 同上 |
二级数据(15 项),加密存储,默认脱敏显示:
| 字段 | 级别 | 实施动作 |
|---|---|---|
| 自然人姓名 | 二级 | 加密存储;显示最后 1-2 个汉字 |
| 自然人登录账号 | 二级 | 加密存储;按账号规则脱敏 |
| 自然人手机号 | 二级 | 加密存储;前 3 后 4 显示 |
| 证件有效日期 | 二级 | 加密存储;显示后 4 位 |
| 证件失效日期 | 二级 | 加密存储;显示后 4 位 |
| 发卡地 | 二级 | 加密存储;按地址规则脱敏 |
| 用户邮箱 | 二级 | 加密存储;保留 @ 及域名 |
| 注册时间 | 二级 | 加密存储;按日期规则脱敏 |
| 用户生日 | 二级 | 加密存储;按日期规则脱敏 |
| 用户学历 | 二级 | 加密存储 |
| 用户支付宝号 | 二级 | 加密存储;显示后 4 位 |
| 用户微信号 | 二级 | 加密存储;显示后 4 位 |
| 用户工作单位 | 二级 | 加密存储;按单位名规则脱敏 |
| 用户第二手机号 | 二级 | 加密存储;前 3 后 4 显示 |
| 用户第三手机号 | 二级 | 加密存储;前 3 后 4 显示 |
把这三张表变成一个可被代码引用的常量,是让定级真正生效的第一步。字典化之后,序列化层、脱敏层、日志层都能统一引用同一个来源,避免三处各写一份、改一处漏两处:
# privacy_level.py —— 按附录 A 落地的字段定级基线,值 1/2/3 对应一/二/三级 LEVEL = { # 三级:可标识自然人且隐私性高,互联网区必须散列存储 "id_no": 3, # 证件编号 "social_card_no": 3, # 社保卡号 "residence_addr": 3, # 户籍地址 "live_addr": 3, # 居住地址 # 二级:可标识且较公开,加密存储 + 默认脱敏 "real_name": 2, "login_account": 2, "mobile": 2, "mobile2": 2, "mobile3": 2, "email": 2, "birthday": 2, "reg_time": 2, "id_valid_from": 2, "id_valid_to": 2, "issue_place": 2, "alipay_no": 2, "wechat_no": 2, "education": 2, "work_unit": 2, # 一级:不能对应到自然人实体 "id_type": 1, "id_hash": 1, "real_level": 1, "verify_time": 1, "gender": 1, "user_type": 1, "nation": 1, "nationality": 1, } def level_of(field: str) -> int: # 未登记字段一律按三级处理:宁可多加密,不可漏判 return LEVEL.get(field, 3)这段代码有两个刻意设计。一是level_of的默认值取 3,新增字段忘记登记时走最严路径,出错方向是“多做一步”而不是“漏保护一个”。二是字典键必须是英文标识而不是中文名,中文名在不同系统里叫法不统一,用它做键迟早对不上。参数上唯一需要团队约定的是字段命名规范,我把mobile2、mobile3对应第二、第三手机号,就是为了和正文措辞保持可追溯。
2.3 表外还有三类数据:儿童、生物特征、访问记录
附录 A 只是“身份模型里”的字段,标准在判定一章另外点了三类表外数据,它们不进主表,但必须进字典。
未满 14 周岁的儿童,标准明确“可提升数据隐私级别”。注意措辞是可提升,不是必须提升;工程上我建议直接提升一级,理由很简单:儿童数据一旦泄露的处置成本远高于多加密一次的存储成本,而且判定年龄依赖生日字段,生日本身是二级,判定链路短,实现起来不复杂。
生物特征分两档:人脸、声纹这类较公开的属二级;指纹这类可作为认定个人信息的属三级。这个区分不是按采集难度,是按可替换性——人脸和声纹在政务场景里常作为核验辅助,指纹往往直接绑定身份认定。落地时最容易漏的是把指纹特征值当普通字符串存进业务库,正确做法是走三级口径。
访问记录属二级:登录记录、政务门户访问记录都算。但它还有一条额外限制——只允许用于异常登录分析和异常处置,不得用于其他用途。这条限制很多人只记住了级别、忘了用途,结果把访问记录接进了用户画像或者推荐位。
3. 存储与密钥:二级加密、三级散列,密钥不进代码库
3.1 三个级别对应三套存储口径,区域不同口径也不同
存储要求分层很清晰,但有一个容易被忽略的细节:标准对三级数据明确区分了互联网区和电子政务外网,对二级数据没有区分区域。三级在互联网区要求不可逆加密,不得明文或可逆加密,且必须用国家节点统一提供的散列函数对明文做散列运算;三级在电子政务外网则以加密方式存储。二级统称“应以加密方式存储”。
| 级别 | 互联网区 | 电子政务外网 | 可逆性 | 算法口径 |
|---|---|---|---|---|
| 一级 | 按通用安全要求 | 按通用安全要求 | 可逆 | 不作特殊要求 |
| 二级 | 加密存储 | 加密存储 | 可逆 | 加密密钥使用 SM2、SM4 |
| 三级 | 散列存储,禁止明文/可逆 | 加密存储 | 互联网区不可逆 | 统一散列函数 + SM2/SM4 |
二级数据没有区分区域,实施时按更严的那一侧做就对了——两边都加密,不留讨论空间。三级数据的可逆性必须在设计阶段定死,因为一旦业务侧提出“证件编号要能回显完整值”,就意味着互联网区不能存明文,只能在用户二次认证后从加密侧取值或者走国家节点查询,架构上前置条件完全不同。
还有一条常被漏掉的保存原则:各节点应按用户信息模型范围收集,节点自己收的数据自己负责安全。这条看着像废话,实际影响的是责任边界——地方和部门节点不能因为“数据最终要上报国家节点”就放松本地存储要求。
3.2 密钥托管与人员边界:密钥管理员为什么不能碰数据
密钥这部分是整份标准里最容易在检查中失分的地方,因为它考的不是技术,是岗位设置。
密钥必须存放在符合 GM/T 0051-2016 的系统或设备中,不能落在配置文件、环境变量、代码仓库里。密钥由专人管理。密钥管理人员不得从事数据操作、加工、使用等工作。密钥管理人员应是本节点正式工作人员,不得来自软件开发商、服务商等第三方机构。加密密钥使用 SM2、SM4 算法。
四句话,四条硬约束。第三条和第四条在项目制交付里几乎必然产生冲突:外包运维团队熟悉密钥设备、熟悉轮换流程,但他们不能当密钥管理员。常见的合规做法是把密钥管理员岗设在甲方正式人员编制里,第三方只承担设备运维和流程支持,不持有密钥操作权限。
落到配置上,策略文件里只写“引用哪个密钥标识、用哪种算法”,不写密钥本身。我给团队的模板大致长这样:
# storage_policy.yaml —— 存储与密钥策略,只写引用不写密钥材料 fields: id_no: # 证件编号,三级 zone: internet storage: hash # 互联网区不可逆 hash_provider: national-node-unified # 统一散列函数,禁止自研 display_mask: tail4 social_card_no: zone: internet storage: hash hash_provider: national-node-unified mobile: zone: both storage: encrypt # 二级,两侧都加密 key_ref: kms://identity/mobile/v1 # 只引用标识 algorithm: SM4 display_mask: mobile_3_4 key_management: device: gm-t-0051-compliant # 符合密钥管理规范的设备 custodian_role: key-admin # 正式人员专岗 forbidden_roles: [data-ops,>MASK = "*" def mask_name(name: str) -> str: # 姓名:两字留最后 1 个汉字,三字及以上留最后 2 个 if not name: return "" keep = 1 if len(name) <= 2 else 2 return MASK * (len(name) - keep) + name[-keep:] def mask_mobile(mobile: str) -> str: # 手机号:前 3 后 4,标准明确不受 50% 下限约束 if len(mobile) != 11: return MASK * len(mobile) return mobile[:3] + MASK * 4 + mobile[-4:] def mask_tail(value: str, keep: int = 4) -> str: # 证件编号、社保卡号、证件有效期、支付宝号、微信号:只留后 4 位 if len(value) <= keep: return MASK * len(value) return MASK * (len(value) - keep) + value[-keep:] def mask_email(email: str) -> str: # 邮箱:保留 @ 及域名,本地部分全部掩码 local, sep, domain = email.partition("@") if not sep: return MASK * len(email) return MASK * len(local) + "@" + domain def mask_address(addr: str) -> str: # 地址/单位/发卡地:>12 字符显示前 6 位;<=12 字符隐藏不少于一半 n = len(addr) if n == 0: return "" if n > 12: return addr[:6] + MASK * (n - 6) hidden = (n + 1) // 2 # 向上取整,保证隐藏比例 >= 50% return addr[: n - hidden] + MASK * hidden逻辑说明:mask_name用len()计数而不是按姓氏语义切分,是为了兼容复姓和带间隔符的姓名;mask_tail的keep参数默认 4,覆盖证件编号、社保卡号、证件有效期、支付宝号、微信号五类字段,字段不同但规则相同,共用一个函数减少分支;mask_address的hidden = (n + 1) // 2是向上取整,n 为奇数时多隐藏一位,确保任何长度都满足“显示不超过 50%”;mask_email用partition而不是split,是为了处理本地部分含点号、加号的邮箱地址。
参数说明与改法:keep只在极少数场景需要调整,标准写的都是后 4 位,不建议动;mask_address里的 12 和 6 是标准给的固定阈值,属于硬编码规则而不是可调参数,别做成配置项让运维随手改,改了就偏离标准;mask_mobile里的长度 11 是国标手机号长度,遇到非 11 位的历史脏数据直接整串掩码,比截断更安全。
验收时我会做三件事:拿线上真实样本跑一遍所有函数,逐条比对标准示例;构造边界样本(1 个字符的姓名、10 个字符的地址、12 个字符的地址、13 个字符的地址、含 @ 但无域名的脏邮箱);把脱敏函数的输出和页面实际显示做一次比对,确认页面没有绕开函数直接取原值。
5. 踩坑排查:五条血泪经验,每条都能让你暂停接入
5.1 工作单位到底是二级还是三级
现象:字段分级评审会上,一份材料说工作单位是三级,另一份说是二级,两边都能在标准里找到依据,开发按三级做了不可逆散列,业务侧要按单位统计时发现原值取不回来,功能直接废掉。
原因:标准正文的定级举例里,把工作单位和证件编号、户籍地址并列提到了“较高隐私性”,而规范性附录的判定表里,用户工作单位明确列为二级。正文是举例说明,附录是逐字段判定表,两者粒度不同。
解决:以附录 A 为准,工作单位按二级处理——加密存储、可逆、默认脱敏显示,脱敏按地址类规则执行。团队内部要立一条规矩:字段级别有歧义时,先查附录 A 的判定表,判定表没列的字段才回到正文看举例,最后按“未登记默认三级”兜底。
5.2 把“不可逆加密”做成了自研散列加盐
现象:三级字段上线半年,跨节点查询全部失败,同一个证件编号在两个节点算出来的散列值对不上,用户信息查询接口返回空结果。
原因:开发团队按“不可逆加密”的字面理解,自己选了散列算法并加了项目自定义盐值。标准的要求是采用国家节点统一提供的散列函数对明文进行散列运算,散列口径必须全网一致,自研等于自断链路。
解决:三级数据的散列必须调用统一提供的散列实现,盐值和参数由统一侧管理,业务侧不参与。改造时同步做两件事:把存量数据按统一函数重算一遍并做双写过渡;在配置里把hash_provider固化为统一标识,禁止业务代码直接引入第三方散列库。
5.3 查询接口写成批量,一条请求带走一页用户
现象:性能压测时有人把用户信息查询接口改成了支持主键列表,一次最多传 50 个用户标识,接口返回列表。功能上线两周后检查中被判定不合规。
原因:标准对查询接口的限制是只允许接收和输出一个用户的个人信息,不得存在一次查询多个用户的服务。这个限制不是性能约束,是防止一次请求批量拉取个人信息。
解决:接口签名回退成单用户主键,批量需求在调用方拆成多次单用户调用,并在网关层加参数校验,检测到数组入参直接拒绝。同时在审计日志里记录每次查询的用户标识和被查用户标识,两者不一致时告警。
5.4 日志留存配了 90 天自动清理
现象:检查要求提供近一年的隐私数据操作日志,翻出来只有最近三个月,其余已被定时任务清理。
原因:日志组件沿用了通用系统的保留策略,没人把它和隐私数据各环节都要记日志、日志保存时间不少于 1 年这条要求对上。
解决:把日志留存周期从通用默认值改为不少于 1 年,超出时效后归档而不是删除。同时补齐日志覆盖面——收集、使用、加工、输出各个环节都要有记录,不能只记登录。日志本身也可能含敏感字段,写日志前先过一遍脱敏函数,别让日志库成了明文泄露点。
5.5 密钥管理员由外包运维兼任
现象:密钥轮换流程走得挺顺,但岗位表一查,密钥管理员是第三方驻场运维,同时还有生产库的数据操作权限。
原因:项目交付期人手紧,谁熟悉密钥设备就谁来管,没人对照“密钥管理人员不得从事数据操作、加工、使用等工作,且应是本节点正式工作人员”这两条硬约束。
解决:密钥管理员岗改由正式人员担任,第三方只做设备运维支持、不持有密钥操作权限;在权限系统里把密钥管理角色和数据操作角色做成互斥,同一账号不能同时授予;轮换、启停、销毁都留双人操作记录。
5.6 排查顺序:从字段表开始,别从代码开始
遇到合规问题,我的排查顺序是固定的:先拉字段分级表核对附录 A,确认每个字段的级别和存储口径没跑偏;再看脱敏函数和页面回显,用边界样本跑一遍;然后查密钥托管位置和管理员岗位;接着查日志留存周期和覆盖面;最后查数据导出记录和销毁流程。这个顺序是按“改一处影响面”排的,越靠前的问题改动成本越低、影响面越大。反过来从代码查起,往往在细枝末节上耗掉两天,回头发现字段级别一开始就定错了。
6. 一张自查表,把验收前的一次性冲刺变成常态
标准落地最常见的失败模式是“检查前突击、检查后回退”。想把这件事做稳,得把检查项变成一张能每周跑一遍的自查表,而不是一份锁在共享盘里的整改报告。
我的做法是把标准条款压成六行,每行带一个可验证的证据物,谁负责、证据在哪、多久看一次都写清楚:
| 检查项 | 判定依据 | 证据物 | 频率 |
|---|---|---|---|
| 字段定级 | 附录 A 逐字段比对 | 字段分级字典与代码引用 | 每次模型变更 |
| 存储口径 | 三级互联网区不可逆、二级加密 | 存储策略配置 + 抽样数据 | 每月 |
| 密钥托管 | 设备合规、管理员岗位互斥 | 密钥台账 + 权限矩阵 | 每季度 |
| 默认脱敏 | 除手机号外隐藏 ≥ 50% | 边界样本跑测报告 | 每次发布 |
| 临时明文配额 | 1000 条 / 24h、8h、2h | 接口限流配置 + 销毁日志 | 每月 |
| 日志与导出 | 日志 ≥ 1 年、导出记录 ≥ 1 年 | 日志保留策略 + 导出台账 | 每季度 |
表格只是骨架,真正管用的是配套的抽样手法。我一般从生产环境抽一条完整链路——一个真实用户的注册、核验、查询、导出四步,然后把这条链路上出现的所有数据副本列出来:业务库、缓存、临时表、日志文件、导出文件、备份。逐份核对它是否落在允许的级别口径内,尤其是缓存和临时文件这两个地方,标准在数据销毁一章专门点了内存残留、缓存、临时文件、临时库表,实际出问题也大多在这几处。归档后形成离线文档、不可在线查询获取这条,同样要落在这份清单里,别让归档库还挂在线上。
差异比对也要做。字段分级字典更新后,跑一遍脚本比对“字典里的级别”和“线上实际存储方式”,任何不一致都当成缺陷单处理。这个脚本很简单:遍历字典,按级别去核对存储表的列类型、是否加密、是否有散列标记,输出差异列表。它的价值不在技术含量,在于把“应该”变成“已经”。
血泪经验是这么来的:早些年我接手一个身份认证节点的整改,前期所有精力都扑在脱敏函数上,验收前一天才发现导出记录只记了操作人和时间,用途、地点、授权信息、导出文件大小、数据数量、个人信息散列值全缺,只能连夜补流程、补字段、补历史台账。从那以后我每次做这类合规落地,都强制先跑一遍“字段—存储—显示—日志—导出—销毁”六段自查,一段不通过就不往下推。这份标准的价值也在这里:它把每一段该长什么样都写死了,剩下的是你愿不愿意把它变成每周的固定动作。希望帮到你。
本文还有配套的精品资源,点击获取