5G核心网安全认证实战:AMF/SMF认证与安全架构落地路径
一次核心网云化后的内部检查,发现了一个让人不太安心的事实:网元之间的服务化接口调用,靠的是"网络可达即信任"——只要地址通、端口开,任何一台接入到这张网络的机器,都能调用 AMF 的服务接口。
没有网元身份校验,没有接口级别的授权,也没有调用留痕。检查组的结论很直接:这套架构把安全边界寄托在"别人进不来"上,而云化环境里,这条边界已经不成立了。
坐标先立:3GPP TS 33.501 定义的核心网安全架构大致分三块:终端与网络之间的认证(主认证与二次认证)、网元之间的身份与接口保护、用户标识与切片的隔离。本篇聚焦中间这块——网元侧。终端接入认证与专网访问控制在 D6-3 里已经展开,这里讲的是核心网内部:网元凭什么互相信任、接口凭什么被授权调用、用户标识怎么在链路上不暴露。
01 | 核心网的安全边界,从"机房围墙"变成"网元身份"
传统核心网的安全模型很像一座机房:边界清晰、设备固定、进出有门禁。网元部署在专属硬件上,网元之间的通信跑在专网里,"能连上"本身就是一种身份证明。
云化与服务化架构(SBA)之后,这个模型不再成立:
- 网元不再固定。虚拟化网元可以按需部署、动态扩缩、跨资源池迁移,"IP 地址等于身份"在这套环境里没有任何意义——地址会变,身份不会。
- 网元之间互相调用。服务化架构把网元能力拆成服务接口,一个网元向多个网元发起调用,调用关系从"固定的几条链路"变成"一张网状图"。任何一处身份校验缺失,都会被这张网放大。
- 用户标识在链路上传递。用户身份标识在接入与信令流程中需要被传递与查询,如果在链路上以明文出现,等于把用户身份暴露在沿途每一个节点上。
- 切片共享同一套基础设施。不同业务切片跑在相同的资源池上,如果隔离只靠配置,一旦授权出错,切片之间就可能互相访问。
这四点带来一个共同结论:核心网的安全边界,已经从"机房围墙"变成了"网元身份"——不再靠"在哪里",而是靠"你是谁、你能做什么"。
5G 核心网的三道门 [门一:网元身份] 网元与网元之间 —— 双向证书认证 │ 解决:是谁在调用我 ▼ [门二:接口授权] 服务化接口调用 —— 令牌 + 服务范围 │ 解决:它能调用我哪些能力 ▼ [门三:标识与隔离] 用户标识与切片 —— 标识隐藏 + 切片授权 解决:用户身份不暴露、切片之间不串02 | 网元之间凭什么互相信任:三层机制
三道门对应三层机制,它们作用在不同层次,缺一层就有一种攻击面裸露在外:
| 层次 | 机制 | 解决什么问题 | 缺失的后果 |
|---|---|---|---|
| 传输层 | 双向证书认证(网元证书) | 通信双方身份真实 | 任意主机可冒充网元接入 |
| 服务层 | 令牌 + 服务范围授权 | 谁能调用哪些接口 | 一个网元被攻破后可调用全网元能力 |
| 标识层 | 用户标识隐藏、切片授权 | 用户身份不暴露、切片不串 | 标识在链路泄露、越权跨切片访问 |
三层机制的思路是一致的:把"网络可达"与"有权访问"彻底分开。网络可达只是前提,能不能建立通道取决于证书,建立通道后能不能调用某个接口取决于令牌里的服务范围,调用时传的数据里用户标识是否可见则取决于标识保护机制。
网元证书和人的证书,有什么不一样
网元证书容易被当成"服务器证书的翻版",但两者的运维方式差别很大:
| 维度 | 人的证书(UKEY/员工) | 网元证书 |
|---|---|---|
| 签发方式 | 人工申请、审核后签发 | 自动化签发,无人工介入 |
| 有效期 | 通常一年以上 | 相对更短,需自动轮换 |
| 数量级 | 百到千级 | 与网元实例数同阶,随扩缩容变化 |
| 吊销时机 | 人员离职、设备丢失 | 实例下线、证书异常、密钥疑似泄露 |
| 私钥位置 | 硬件介质内 | 网元安全模块或硬件密码模块内 |
差异集中在两点:一是自动化——网元实例随扩缩容动态产生,证书不可能靠人工申请;二是短周期与即时吊销——网元证书一旦泄露,影响面比单个员工账号大得多,吊销必须是分钟级生效,而不是等下一次同步。
密钥分层:网元侧的三级密钥关系
核心网里跑的密钥不止一种,它们之间是有层级的。层级分不清,就会出现"拿会话密钥去加密长期存储数据"这类错配:
| 层级 | 作用 | 存放位置 | 生命周期 |
|---|---|---|---|
| 根密钥 | 保护下层的密钥 | 硬件密码模块内,不以明文外出 | 长期,极少更换 |
| 网元密钥 | 网元身份与通道保护 | 网元安全模块 / 硬件密码模块 | 与证书有效期同步,自动轮换 |
| 会话密钥 | 单次会话的数据保护 | 会话建立时协商产生 | 一次会话,用后销毁 |
层级关系的意义在于:任何一把下层密钥泄露,都不能直接推出上层密钥。会话密钥泄露只影响当前这次会话;网元密钥泄露影响该网元,需要立即轮换并吊销证书;根密钥始终留在硬件里,不参与具体业务运算。演示环节 5 里"旧会话密钥解不开新会话数据",对应的就是最下层的隔离效果。
03 | 先跑通:网元认证与授权的五个环节
下面这段用国密算法把五个环节跑一遍:网元双向认证、服务化接口授权、用户标识隐藏、切片授权隔离、会话密钥轮换(演示用固定密钥与测试标识):
# -*- coding: utf-8 -*- # 5G 核心网网元认证演示(国密 SM2/SM3/SM4) # 场景:网元双向认证 + 服务化接口授权 + SUPI 隐藏 + 切片授权 + 会话密钥轮换 import json from gmssl import sm2, sm3, sm4, func def sm3h(b: bytes) -> str: return sm3.sm3_hash(func.bytes_to_list(b)) def digest(b: bytes) -> bytes: return bytes.fromhex(sm3h(b)) def sm4_enc(k: bytes, b: bytes) -> bytes: c = sm4.CryptSM4(); c.set_key(k, sm4.SM4_ENCRYPT); return c.crypt_ecb(b) def sm4_dec(k: bytes, b: bytes) -> bytes: c = sm4.CryptSM4(); c.set_key(k, sm4.SM4_DECRYPT); return c.crypt_ecb(b) def try_dec(k: bytes, b: bytes): try: return sm4_dec(k, b) except Exception: return None def try_dec_sm2(c, b: bytes): try: return c.decrypt(b) except Exception: return None def pub_of(p: str) -> str: return sm2.CryptSM2(private_key=p, public_key="00")._kg(int(p, 16), sm2.default_ecc_table["g"]) def line(t: str, ok: bool): print(f"[{t}] = {'True' if ok else 'False'}") # 网元证书私钥(实际存于网元安全模块/HSM,永不明文出硬件) AMF_P = "5a6b7c8d9e0f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3" SMF_P = "6b7c8d9e0f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4" ROGUE_P = "7c8d9e0f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5" # 未获授权的第三方网元 K_SIGN = "20240601123456789abcdef0123456789abcdef0123456789abcdef012345678" AMF = sm2.CryptSM2(private_key=AMF_P, public_key=pub_of(AMF_P)) SMF = sm2.CryptSM2(private_key=SMF_P, public_key=pub_of(SMF_P)) ROGUE = sm2.CryptSM2(private_key=ROGUE_P, public_key=pub_of(ROGUE_P)) # 各网元只持有对端证书里的公钥 AMF_HOLDS_SMF = sm2.CryptSM2(private_key=None, public_key=pub_of(SMF_P)) SMF_HOLDS_AMF = sm2.CryptSM2(private_key=None, public_key=pub_of(AMF_P)) print("== 环节1:网元双向认证(证书身份) ==") N1 = "7f3a91c2e5b04d68a1f7c3902b6e5d41" # AMF 下发的随机挑战 N2 = "c04b8e15d7a92f6301e8b4c7d29f5063" # SMF 回敬的随机挑战 sig_smf = SMF.sign(digest(N1.encode()), K_SIGN) line("SMF 身份校验通过(AMF 侧)", AMF_HOLDS_SMF.verify(sig_smf, digest(N1.encode()))) sig_amf = AMF.sign(digest(N2.encode()), K_SIGN) line("AMF 身份校验通过(SMF 侧,双向)", SMF_HOLDS_AMF.verify(sig_amf, digest(N2.encode()))) sig_rogue = ROGUE.sign(digest(N1.encode()), K_SIGN) line("伪造网元 冒充 SMF 失败", not AMF_HOLDS_SMF.verify(sig_rogue, digest(N1.encode()))) print("== 环节2:服务化接口授权(令牌 + 服务范围) ==") def issue(entity, scope: str, exp: int): payload = json.dumps({"nf": entity, "scope": scope, "exp": exp}, ensure_ascii=False, sort_keys=True) return payload + "." + entity_sign(entity, payload) def entity_sign(entity: str, payload: str) -> str: priv = {"SMF": SMF_P}[entity] s = sm2.CryptSM2(private_key=priv, public_key=pub_of(priv)) return s.sign(digest(payload.encode()), K_SIGN) def grant(token: str, need: str, now: int) -> bool: try: payload, s = token.rsplit(".", 1) p = json.loads(payload) except Exception: return False ok_sig = AMF_HOLDS_SMF.verify(s, digest(payload.encode())) return ok_sig and p["scope"] == need and p["exp"] > now TOKEN = issue("SMF", "namf-comm", 1000) line("合法令牌 授权通过", grant(TOKEN, "namf-comm", 500)) line("越权服务范围 授权拒绝", not grant(TOKEN, "namf-oam", 500)) line("令牌超期 授权拒绝", not grant(TOKEN, "namf-comm", 1500)) print("== 环节3:SUPI 隐藏(空口只传 SUCI) ==") SUPI = b"imsi-001010000000001" # 演示用测试标识 UDM_P = "8d9e0f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6" UDM = sm2.CryptSM2(private_key=UDM_P, public_key=pub_of(UDM_P)) SUCI = UDM.encrypt(SUPI) # 用归属网络公钥加密 line("空口传输的是 SUCI 密文", SUCI != SUPI) line("归属网络 可还原 SUPI", UDM.decrypt(SUCI) == SUPI) OTHER = sm2.CryptSM2(private_key=None, public_key=pub_of(AMF_P)) line("非归属网元 解不出 SUPI", try_dec_sm2(OTHER, SUCI) != SUPI) print("== 环节4:切片授权隔离 ==") SLICE_GRANT = {"SMF-01": ["01-000001"], "AMF-01": ["01-000001", "02-000001"]} def slice_ok(nf: str, sst: str) -> bool: return sst in SLICE_GRANT.get(nf, []) line("网元访问本切片 放行", slice_ok("SMF-01", "01-000001")) line("跨切片未授权 拒绝", not slice_ok("SMF-01", "02-000001")) print("== 环节5:会话密钥与轮换 ==") K_SESS_1 = bytes.fromhex("aa" * 16) K_SESS_2 = bytes.fromhex("bb" * 16) UP = ("用户面数据|SUPI=imsi-001010000000001|用量=128MB").encode("utf-8") ct1 = sm4_enc(K_SESS_1, UP) line("会话密钥 加密通道可还原", sm4_dec(K_SESS_1, ct1) == UP) ct2 = sm4_enc(K_SESS_2, UP) # 新一轮会话使用新密钥 line("轮换后 新会话用新密钥", sm4_dec(K_SESS_2, ct2) == UP) line("旧会话密钥 解不开新会话数据", try_dec(K_SESS_1, ct2) != UP)跑起来,五个环节的结论如下:
== 环节1:网元双向认证(证书身份) == [SMF 身份校验通过(AMF 侧)] = True [AMF 身份校验通过(SMF 侧,双向)] = True [伪造网元 冒充 SMF 失败] = True == 环节2:服务化接口授权(令牌 + 服务范围) == [合法令牌 授权通过] = True [越权服务范围 授权拒绝] = True [令牌超期 授权拒绝] = True == 环节3:SUPI 隐藏(空口只传 SUCI) == [空口传输的是 SUCI 密文] = True [归属网络 可还原 SUPI] = True [非归属网元 解不出 SUPI] = True == 环节4:切片授权隔离 == [网元访问本切片 放行] = True [跨切片未授权 拒绝] = True == 环节5:会话密钥与轮换 == [会话密钥 加密通道可还原] = True [轮换后 新会话用新密钥] = True [旧会话密钥 解不开新会话数据] = True逐段注解:环节 1 演示的是双向认证——AMF 校验 SMF 的身份,SMF 同时校验 AMF 的身份,两边各持对方证书里的公钥,自己的私钥留在安全模块内。第三条是关键:一个未获授权的网元即便能接入网络,没有对应私钥就签不出能被接受的签名。这正是"网络可达 ≠ 有权访问"的技术落点。环节 2 把授权从传输层提到服务层:令牌里写明"哪个网元、能调用哪些服务范围、什么时候过期",三条同时满足才放行。第二条尤其值得注意——篡改服务范围会让签名校验直接失败,因为签名覆盖了整个令牌内容,而不是只覆盖了其中一部分;第三条演示超期拒绝,避免令牌被长期复用。环节 3 处理用户标识:标识在链路上以密文形态传递,只有归属网络的网元能用私钥还原,沿途经过的其他网元拿到的是一段解不开的密文——这就是"标识隐藏"的实际效果。环节 4 演示切片授权:同一张网络上,网元能访问哪些切片由授权关系决定,跨切片访问默认拒绝,隔离不依赖"配置没写错"。环节 5 是会话密钥的轮换:新一轮会话使用新密钥,旧密钥解不开新会话的数据,单次会话密钥泄露不会影响后续会话。
验证点(现场怎么演):用一台不在网元清单里的主机去调用服务接口,应当在证书校验阶段就被拒绝;把令牌里的服务范围改成未授权值,应当被拒绝;抓取信令链路,用户标识字段应当是密文;用未授权切片标识发起访问,应当被拒绝;查看网元证书,应当能看到签发者、有效期与吊销状态。
网元证书的生命周期怎么走
把证书体系落到运维上,四个动作必须自动化,否则规模化之后必然失控:
| 动作 | 触发时机 | 关键要求 |
|---|---|---|
| 签发 | 网元实例创建 | 与实例标识绑定,由证书系统自动签发 |
| 轮换 | 到期前自动触发 | 不中断业务,新旧证书有重叠期 |
| 吊销 | 实例下线、密钥疑似泄露 | 分钟级生效,避免"已下线仍能访问" |
| 审计 | 每次证书操作 | 谁在什么时候签发/吊销了哪张证书,可追溯 |
其中吊销的生效速度最容易被低估。网元实例下线后,如果证书要等到过期才失效,这段窗口里旧证书仍然可用——实例虽然关了,但拿着一张还没过期的证书和对应的私钥,照样能建立通道。所以吊销必须是主动推送、即时生效,而不是"依赖过期时间兜底"。
04 | 落地动作:三条线分别怎么做
身份线:让每个网元都有可信身份
- 一实例一证书:证书与网元实例绑定,私钥在网元侧安全模块或硬件密码模块内生成与保存,不以明文形式落到文件系统。
- 自动化签发与轮换:通过证书管理能力对接资源编排流程,实例创建即签发、到期前自动轮换,运维人员不接触私钥。
- 即时吊销:实例下线、异常检测、密钥疑似泄露时主动吊销,并确保各网元及时刷新信任列表。
- 证书生命周期留痕:签发、轮换、吊销全程记录,便于事后核查与合规举证。
授权线:让接口调用可授权、可追溯
- 接口粒度授权:按网元与服务范围划分权限,一个网元只拿到它真正需要调用的服务范围,避免"一个网元被攻破、全网元能力可用"。
- 令牌短周期:令牌有效期设短,过期需重新获取;避免长期有效的令牌在链路中反复使用。
- 调用留痕:谁调用了谁、什么时间、什么服务范围、结果如何,记录并保护其完整性,作为异常行为的追溯依据。
- 切片隔离落到授权:切片之间的访问关系用授权表达,新切片上线时默认拒绝跨切片访问,而不是默认放通再逐个收紧。
标识线:让用户身份不在链路上裸奔
- 标识隐藏常态化:用户标识在链路上以密文形态传递,只有归属网络的网元可以还原。
- 按需解密、最小暴露:需要用到用户标识的网元才申请解密能力,其余节点只处理密文。
- 与其他标识分开管理:用户标识、设备标识、切片标识分属不同管理维度,避免一处泄露带来全量关联。
跨域互联:运营商之间怎么保护信令
当业务需要跨网络互通(例如漫游或跨运营商业务),信令要经过网络边界。这条链路上的保护要点是:边界处的身份校验不能省——跨域互通的两端需要有明确的身份认证与消息保护机制,而不是依赖链路本身的私密性。同时,跨域传递的用户标识范围要按业务最小化,能不带就不带,必须带时确保以受保护的形态传递。
运维面怎么收口
网元自身的运维通道(网管、编排、配置下发)是另一条高危路径,核心网里被滥用的运维账号往往比外部攻击更接近数据。网管侧的访问控制与双因素认证做法与专网场景相通(详见 D6-3):权限按角色划分、高危操作二次确认、全量操作留痕。区别在于核心网的网管权限更集中,一个账号可能触及多个网元的配置,因此角色划分要更细、审批链路要更严。
边缘节点下沉之后,认证链路有什么变化
5G 边缘计算把一部分网元能力下沉到靠近现场的节点,认证链路随之变化:
- 沿途节点更多。数据不再只经过中心机房,链路上可能经过多个边缘节点,标识与数据的保护范围要覆盖到边缘侧,而不是到中心为止。
- 物理环境更弱。中心机房的物理防护条件通常好于现场机房或一体化机柜,边缘节点上的密钥存储更依赖硬件保护,不能只靠文件权限。
- 带宽与时延受限。边缘到中心的链路不适合承载大量证书申请与吊销同步操作,证书与密钥管理需要支持本地缓存与断链续传,避免链路抖动导致认证不可用。
- 授权边界要显式。边缘节点既服务本地低时延业务,又可能与中心网元通信,授权关系不能默认放通,而要逐条显式声明。
边缘场景的安全要求可与 GB/T 42564(边缘计算安全)对照落实。判断标准在哪儿都一样:节点有没有可信身份、私钥在不在硬件里、授权是不是显式的。
一个落地样本:从"网络可达即信任"到"一实例一证"
某运营商核心网完成云化后,网元实例随业务需要动态扩缩。原先网元之间靠地址段互信的做法在一次内部检查中暴露了问题:说不清"谁调用过谁",也无法在实例下线后立即切断访问。
整改按三步走:先给每个网元实例签发独立证书,私钥在安全模块内生成与保存,不进文件系统;再把接口调用改为按服务范围授权,令牌有效期缩短、过期即失效;最后把证书的签发、轮换、吊销纳入自动化流程——实例创建即签发、到期前自动轮换、下线即吊销,全过程留痕。
结果:实例下线后旧证书即时失效,不再出现"实例已经关了、凭旧证书仍能建立通道"的情况;接口调用关系可以按服务范围逐条核对;一旦出现异常调用,能通过记录回溯到具体实例。
05 | 避坑清单:8 条最容易踩的坑
| # | 坑 | 后果 | 怎么验证避开了 |
|---|---|---|---|
| 1 | 网元间只做单向认证 | 一方身份可被冒充 | 检查配置,应双向校验证书 |
| 2 | 私钥以文件形式存放在网元上 | 备份或镜像泄露即私钥泄露 | 排查文件系统,私钥应在硬件内 |
| 3 | 证书长期有效、不轮换 | 泄露后长期可用 | 查看证书有效期与轮换记录 |
| 4 | 实例下线不吊销证书 | 已下线实例仍可建立通道 | 下线实例后尝试连接,应被拒绝 |
| 5 | 所有网元共用一张证书 | 一处泄露全网元失守 | 核对证书与实例的对应关系 |
| 6 | 接口授权粒度粗、按网元整体放通 | 一个网元被攻破即全网元可达 | 检查授权范围是否按服务细分 |
| 7 | 令牌有效期过长 | 令牌泄露后可长期冒用 | 检查令牌有效期与刷新机制 |
| 8 | 只保护外部接口,内部调用不留痕 | 异常调用事后无法追溯 | 抽查调用记录是否完整可查 |
第 5 条在实践中并不少见:为了省事,一批网元共用一张证书。短期看运维简单,代价是一旦其中一个实例的私钥泄露,攻击者可以用同一张证书冒充这一批里的任意一个网元,排查时也分不清到底是哪个实例出了问题。
06 | 合规视角:核心网要对上哪些要求
- 3GPP TS 33.501:5G 系统安全架构与流程的技术依据,涵盖终端认证、网元间安全、用户标识保护等内容,是核心网安全设计的主要参照。
- YD/T 4204 等行业标准:面向 5G 核心网安全的行业要求,落地时需与 3GPP 体系结合使用。
- GB/T 42564(边缘计算安全):涉及边缘计算场景时,边缘节点与核心网之间的身份与数据保护要求需要一并考虑。
- 等保 2.0 与关基保护要求:电信网络属关键信息基础设施范畴,核心网系统普遍按等保三级及以上定级,身份鉴别、访问控制、通信加密、审计留痕都是明确测评项。
- 密评要求:密码应用层面需按 GB/T 39786 落实算法合规、密钥管理与有效性验证(整改与算法迁移路径详见 D7-1)。
07 | 落地答案:身份认证与密码运算怎么承接
把三道门落到组件上,安当体系里对应 ASP 与 HSM 两件:
- ASP 统一身份认证平台:提供统一身份管理与认证能力,支撑网元与运维账号的身份认证、令牌签发与权限划分;支持双因素认证与 RADIUS 等对接方式,可用于网管与运维通道的访问控制。对应"门一"与"门二"的身份与授权。
- HSM 硬件密码模块:网元证书私钥与签名运算在硬件内完成,私钥不以明文形态离开硬件;提供签名验签与加解密能力,支撑网元间的双向认证与信令保护。对应避坑第 2 条。
- KSP 密钥管理系统:统一管理网元证书相关的密钥与会话密钥,支持版本化轮换、归档与操作留痕(全生命周期做法详见 D6-2)。对应"门三"的会话密钥与会话隔离。
一句话:这套组合要解决的是"每个网元都有可信身份、每次调用都有授权依据、每段标识都不裸奔"——三件事同时成立,核心网的安全才不依赖于"别人进不来"。
08 | 验收清单与下一步
| 检查项 | 当场动作 | 应得结果 |
|---|---|---|
| 双向认证 | 检查网元间通信配置 | 双方互验证书 |
| 私钥保护 | 排查网元文件系统 | 无私钥明文 |
| 一实例一证 | 核对证书与实例 | 一一对应,无共用 |
| 证书轮换 | 查看轮换记录 | 有周期、有重叠期 |
| 吊销生效 | 下线实例后尝试连接 | 被拒绝 |
| 接口授权 | 用未授权服务范围调用 | 被拒绝 |
| 令牌超期 | 用过期令牌调用 | 被拒绝 |
| 标识隐藏 | 抓取链路查看标识字段 | 密文 |
| 切片隔离 | 跨切片发起访问 | 被拒绝 |
| 调用留痕 | 抽查调用记录 | 完整可查 |
趋势:核心网的安全正在从"静态边界防护"走向"持续身份验证"——网元身份随实例动态变化,授权随调用关系动态调整,信任不再是一次性建立的,而是每一次调用都要重新确认。早一步把证书体系、接口授权与标识保护建起来,后面无论是切片扩容、边缘节点下沉还是跨域互通,都是在既有地基上叠加。
下一篇预告:电信线的核心网部分到此告一段落。下一篇我们把视角切回公共事业——燃气 SCADA 与调度数据的安全防护,看工控场景下的操作员认证与数据保护有哪些不一样的门道:为什么工控现场不能照搬 IT 的做法、老旧设备的认证怎么补、现场数据怎么做到既加密又不影响实时性。
文章作者:安当加密-焱垚