在5G漫游场景中,UE的PLMN选择(驻留哪个运营商网络)直接决定漫游结算收益归属。归属网络(HPLMN)希望把漫游用户"引导"到自己签约的、资费更优的合作伙伴网络上;而拜访网络(VPLMN)出于自身利益,有强烈动机篡改甚至伪造"优选PLMN列表",让UE长期驻留在能给自己带来分成的网络上。在没有完整性保护的时代,这种"漫游引导"(Steering of Roaming,SoR)实际上是可以被VPLMN中间人攻击的——它篡改下发给UE的列表,UE无从分辨真伪。
3GPP在TS 33.501中专门为这个问题设计了独立的安全机制(§6.14),其核心思想只有一句话:只有真正持有用户长期密钥的归属网络(AUSF),才能为SoR列表"盖章"(MAC),UE只认这个章,拜访网络只能当透明的"快递员"。 本文基于TS 33.501 V18.10.0(Release 18)、TS 24.501、TS 23.122与TS 23.502,逐条拆解这套机制的密钥推演、信令流程、IE结构与抓包排错要点。
值得一提的是,SoR与另一组机制UPU(UE Parameters Update,§6.15)是一对"姊妹"设计:UPU-MAC的KDF结构与SoR完全同构(Annex A.19/A.20对应A.17/A.18),只是UPU用于推送UE参数更新(如路由指示、默认配置的NSSAI),SoR用于推送漫游优选列表。理解了SoR,UPU也就通了。
要理解SoR,必须先看懂它的密钥选择。5G主认证后建立的密钥层级是:
K(永久) → K_AUSF → K_SEAF → K_AMF → {K_NAS_int, K_NAS_enc, K_gNB ...}
关键点在于密钥的可见性边界: - K_AUSF:仅在UE与归属网络的AUSF之间共享。 - K_SEAF / K_AMF:在漫游时由AUSF下发给拜访网络的SEAF/AMF,即VPLMN完全掌握。
如果把SoR的MAC用K_AMF或K_SEAF来算,那么掌握这些密钥的VPLMN就能自己伪造一个合法的MAC——这正是要防的攻击!所以SoR刻意选用K_AUSF:这是密钥层级中"拜访网络永远摸不到"的最高一级密钥。于是:
SoR-MAC-I_AUSF,VPLMN无密钥、无法伪造;这就是SoR安全性的根基:用密钥的"不可见性"换取"不可伪造性"。下面所有KDF细节都围绕K_AUSF展开。
5G KDF基于HMAC-SHA-256(TS 33.501 Annex B.2),输入串 S = FC || P0 || L0 || P1 || L1 || ...,取输出的相应低位作为派生密钥/MAC。
这是AUSF为下发列表盖的"章",UE据此验真:
| 参数 | 取值 | 说明 |
|---|---|---|
| 输入密钥 KEY | K_AUSF | 拜访网络不可见 |
| FC | 0x77 | SoR-MAC-I_AUSF 的固定区分符 |
| P0 | SoR header | A.17中的SoR头(含List type/ACK指示等) |
| L0 | length of SoR header | |
| P1 | Counter_SoR | 16位新鲜性计数器 |
| L1 | length of Counter_SoR | |
| P2 | SOR transparent container中"第22字节之后"的内容 | 见TS 24.501 §9.11.3.51 |
| L2 | P2中list数据的长度 | |
| 输出 | 输出的128个最低有效位 | 即16字节MAC |
注意一个精妙设计:P2取的是"容器第22字节之后"的部分。这是因为容器前22字节是固定的元信息(IEI/长度/SoR header/MAC/Counter),真正可变的有效载荷(优选PLMN列表或secured packet)从第23字节开始,所以MAC只对"业务内容"做保护,同时header和Counter单独作为P0/P1计入——既避免冗余,又把所有影响UE决策的字段都覆盖到。
UE成功验证并应用列表后,要给网络一个"我确实收到了"的回执,回执里也带一个MAC,由UE用K_AUSF算出:
| 参数 | 取值 | 说明 |
|---|---|---|
| 输入密钥 KEY | K_AUSF | |
| FC | 0x78 | 与0x77区分方向 |
| P0 | 0x01 | 固定值,含义"SoR Acknowledgement: Verified the Steering of Roaming Information successfully" |
| L0 | 0x00 0x01 | 长度=1 |
| P1 | Counter_SoR | 与下行同一个Counter |
| L1 | length of Counter_SoR | |
| 输出 | 输出的128个最低有效位 | 16字节 |
网络侧(AUSF)用同样输入算出 SoR-XMAC-I_UE 与UE上报的 SoR-MAC-I_UE 比对,确认UE真的处理了这份列表。这解决了"列表到底有没有生效"的可观测性问题——运营商可以据此计费/审计引导成功率。
光有MAC还不够。设想VPLMN截获一份历史上合法的SoR列表(带合法MAC),日后反复重放给UE——只要MAC不变,UE就会一直接受过时列表。Counter_SoR就是为此设计的"新鲜性令牌":
0x00 0x00;AUSF在控制面SoR方案下新K_AUSF存储时初始化为 0x00 0x01;这一组规则构成一个简洁的单调递增状态机:合法列表的Counter必然递增,重放的Counter必然≤已存值而被拒,且即便攻击失败也不会污染UE的计数器。16位计数器对K_AUSF生命周期(一次主认证周期)内的SoR更新次数绰绰有余。
SoR有两条下发路径:注册期(在REGISTRATION ACCEPT中捎带)和注册后(DL NAS TRANSPORT独立下发)。下图合并展示主流的"注册期下发+注册后更新"双路径与回执链路。
sequenceDiagram
autonumber
participant UE
participant AMF as AMF (VPLMN)
participant UDM as UDM (HPLMN)
participant AUSF as AUSF (HPLMN)
Note over UE,AUSF: 前置:主认证完成,UE与AUSF共享K_AUSF
UDM->>AUSF: Nausf_SoRProtection_Get<br/>(SoR header, 优选PLMN列表, ACK指示)
AUSF->>AUSF: Counter_SoR++ ; KDF(K_AUSF, FC=0x77, ...)<br/>生成 SoR-MAC-I_AUSF
AUSF-->>UDM: SoR-MAC-I_AUSF, Counter_SoR
UDM->>AMF: Nudm_SDM_Get / N1N2MessageTransfer<br/>(SOR transparent container, 透传)
AMF->>UE: REGISTRATION ACCEPT<br/>(Payload container = SOR transparent container)
UE->>UE: KDF(K_AUSF, FC=0x77) 算 XMAC<br/>校验 Counter_SoR>已存 且 MAC相等
Note over UE: 验证通过→应用优选列表(TS 23.122)<br/>存储Counter_SoR
UE->>UE: KDF(K_AUSF, FC=0x78) 算 SoR-MAC-I_UE
UE->>AMF: REGISTRATION COMPLETE<br/>(上行SOR transparent container = 回执MAC)
AMF->>UDM: N1MessageNotify (回执)
UDM->>AUSF: Nausf_SoRProtection_Verify
AUSF->>AUSF: 算 SoR-XMAC-I_UE 比对
AUSF-->>UDM: 验证结果(引导是否生效)
Note over UE,UDM: ——注册后更新(独立路径)——
UDM->>AUSF: Nausf_SoRProtection_Get (新列表)
AUSF-->>UDM: 新 SoR-MAC-I_AUSF + 新Counter_SoR
UDM->>AMF: Namf_Communication_N1N2MessageTransfer(N1消息)
AMF->>UE: DL NAS TRANSPORT (Payload container=SOR container)
UE->>AMF: UL NAS TRANSPORT (上行回执MAC)
AMF->>UDM: 回执转发
几个关键节点说明: - 第2步UDM是"请求方NF"(requester NF),SoR header可由UDM构造、也可由AUSF根据收到的ACK指示与列表自行构造(A.17原文)。 - 第4步AMF对容器内容完全不理解、不解析、不修改——它只是按Payload container的"container type=SOR transparent container"原样搬运。这正是安全边界:AMF即使想篡改也无能为力,因为篡改后MAC对不上。 - 第6步UE的验算与第3步AUSF的计算使用完全相同的输入(K_AUSF、FC=0x77、header、Counter、列表字节),故XMAC与MAC必相等——这是HMAC-SHA-256的确定性保证。 - 第8-10步回执链路让HPLMN获得"引导成功"的确认,可对接计费/分析系统。
该IE是type 6信息元素(长度可变,带2字节长度域),最小长度20字节。其经典布局(List type=1,承载PLMN/access technology列表)如下:
flowchart TB
subgraph CT["SOR transparent container (TS 24.501 §9.11.3.51)"]
direction TB
O1["octet 1<br/>SOR transparent container IEI"]
O23["octet 2-3<br/>Length of contents"]
O4["octet 4<br/>SoR header<br/>(List type / SOR data type / ACK指示 / 各SI标志位)"]
O520["octet 5-20<br/>SoR-MAC-I<sub>AUSF</sub> (16字节=128bit)"]
O2122["octet 21-22<br/>Counter<sub>SoR</sub> (16bit)"]
O23n["octet 23* - m*<br/>Length + PLMN ID and access technology list<br/>(或 secured packet,List type=0时)"]
Oo["octet o* ...<br/>(可选) SOR-CMCI / SOR-SNPN-SI / SOR-SNPN-SI-LS"]
end
style O520 fill:#ffd6d6,stroke:#b30000
style O2122 fill:#fff2cc,stroke:#bf9000
style O4 fill:#d9ead3,stroke:#38761d
对应的IE参数说明表:
| 字段(字节位置) | 含义 | 取值/说明 |
|---|---|---|
| IEI(octet 1) | 信息元素标识 | 标识"这是SOR transparent container" |
| Length(octet 2-3) | 内容长度 | type 6 IE固定2字节长度域 |
| SoR header(octet 4) | 头部比特域 | List type(0=secured packet,1=PLMN/接入技术列表)、SOR data type、ACK指示、及新版本SOR-CMCI/SOR-SNPN-SI等标志位 |
| SoR-MAC-I_AUSF(octet 5-20) | 下行MAC | AUSF用K_AUSF、FC=0x77算出,128bit |
| Counter_SoR(octet 21-22) | 新鲜性计数器 | 16bit单调递增,防重放 |
| 有效载荷(octet 23-m) | 优选列表/secured packet | List type=1时为"长度+PLMN ID与接入技术优先级列表";List type=0时为secured packet |
| 可选扩展(octet o*+) | SOR-CMCI 等 | R17+扩展:公共凭证标识、SNPN相关引导信息 |
注意上行(回执)容器更精简:只含IEI/长度/header/SoR-MAC-I_UE(FC=0x78算出的回执MAC),不再带列表。
UE收到容器后的处理是一个明确的判定流程,下图给出其决策路径(结合§6.14.2.3的Counter规则):
flowchart TD
A["收到 REGISTRATION ACCEPT / DL NAS TRANSPORT<br/>含 SOR transparent container"] --> B{"Counter_SoR > 已存值?"}
B -- 否 --> R1["拒绝(疑似重放)<br/>不更新,不上报回执"]
B -- 是 --> C["用本地 K_AUSF、FC=0x77 算 XMAC"]
C --> D{"XMAC == 收到的 SoR-MAC-I_AUSF?"}
D -- 否 --> R2["验证失败:丢弃<br/>不存储Counter,不上报回执"]
D -- 是 --> E["存储新 Counter_SoR<br/>(仅验签成功才存)"]
E --> F["按 TS 23.122 应用优选PLMN/接入技术列表"]
F --> G["FC=0x78 算 SoR-MAC-I_UE"]
G --> H["发 REGISTRATION COMPLETE / UL NAS TRANSPORT 带回执"]
style R1 fill:#f4cccc
style R2 fill:#f4cccc
style E fill:#d9ead3
style F fill:#d9ead3
设计意图小结:步骤B(先比Counter)和步骤E(验签成功才存Counter)联合起来,把"重放"和"状态毒化"两类攻击都堵死——即便攻击者伪造一个超大Counter,由于没有K_AUSF算不出正确MAC,会在步骤D失败,UE也不会存储这个大Counter,下次真正合法的列表仍能被接受。
| 维度 | SoR(漫游引导) | 传统EHPLMN/EPLMN/UEL优先级 | UPU(UE参数更新) | NCCoC/Network Configuration |
|---|---|---|---|---|
| 规范 | TS 33.501 §6.14 + A.17/A.18 | TS 23.122 / USIM文件 | TS 33.501 §6.15 + A.19/A.20 | TS 31.102/31.111 |
| 下发内容 | 优选PLMN/接入技术列表 | UE/USIM预置,静态 | 路由指示、默认NSSAI等UE参数 | 网络配置数据 |
| 安全密钥 | K_AUSF(拜访网不可见) | 无密码学保护 | K_AUSF(与SoR同构) | 依赖secured packet/USIM |
| 防重放 | 16位Counter_SoR单调递增 | 无 | 16位Counter_UPU | 视实现 |
| 触发时机 | 注册期/注册后均可 | 仅UE本地选择 | 注册期/注册后 | OTA/管理面 |
| 设计目标 | 防VPLMN篡改引导,保护HPLMN结算收益 | 简单优先级,无防篡改 | 安全推送UE运行参数 | 灵活配置 |
一个常被忽略的对比是为何SoR不用secured packet(USIM OTA式)而要新建机制:secured packet依赖USIM与HPLMN间的长期密钥、走SIM卡应用层,更新慢、且依赖USIM能力;而SoR走5G NAS层、用主认证刚建立的K_AUSF,注册后即可立即生效、无需USIM OTA往返,更适合"实时引导漫游"这种对时延敏感的商业场景。
在Wireshark/TShark中(5G NAS dissector)识别SoR流程:
Registration accept 或 DL NAS TRANSPORT 消息;Payload container → Payload container type 应为 "SOR transparent container"(区别于N1 SM info、UE parameters update等);SOR-MAC-I(16字节)、Counter(2字节)、List type、SOR data type、ACK 指示位;
- 若List type=1,后面跟着 Length of PLMN ID and access technology list 与各 PLMN ID + Access technology 条目(MCC/MNC + 接入技术标识)。Registration complete 或 UL NAS TRANSPORT,其 Payload container type = SOR transparent container,内含 SOR-MAC-I 回执(FC=0x78计算),通常不含列表。快速TShark过滤示例:
# 抓取所有承载SOR透明容器的NAS消息
tshark -i <iface> -Y "nas_5gs.payload_container_type == 4" -V
# (注:container type 4 在多数版本dissector中映射为SOR,5为UPU;以实际版本为准)
识别要点:SoR消息总是出现在N1(NAS)层、总是封装在Payload container里、AMF侧不解析内容——所以你在N2(NGAP)或N11(AMF-UDM SBI)上看到的是"透传"形态。
故障1:UE不应用新SoR列表(引导失效)。 最常见原因是MAC验证失败。排查方向: - 用抓包确认下行容器完整传输(未在SBI/N2被截断); - 核对AUSF侧K_AUSF是否与UE一致(若中间发生再认证、K_AUSF更新但Counter未同步,会失配); - 检查AUSF的Counter_SoR与UE已存值:若因掉电、双注册等原因UE的Counter"超前"(大于AUSF),则AUSF后续列表Counter恒≤UE,UE会一直拒绝——需触发重新主认证重置K_AUSF+Counter。
故障2:Counter回卷/重置后列表被持续拒绝。 按§6.14.2.3,Counter绑定K_AUSF生命周期。新主认证→新K_AUSF→Counter重置(UE为0x0000,AUSF控制面为0x0001)后应恢复正常。若仍拒绝,检查UE是否把Counter存到了非易失存储(规范要求:支持5G扩展存储的USIM存USIM,否则存ME非易失内存)——存到易失内存会在重启后回零,造成与网络不同步。
故障3:组合注册时延异常增大(约数十秒)。 GSMA IR.73实测指出:在组合注册(Combined Registration)上叠加SoR流程,会带来约75秒量级的注册时延。根因是SoR回执要等REGISTRATION COMPLETE,而组合注册的EPS/5GS协调拉长了窗口。优化建议:把SoR放到注册后用DL NAS TRANSPORT下发,避免阻塞初始注册;或调整ACK指示策略(不强求每次都回ACK)。
故障4:VPLMN漫游引导"看起来生效但资费仍是旧伙伴"。 这是经典的VPLMN侧篡改未遂但UE仍按本地EHPLMN/EPLMN旧优先级选网的情况。需确认UE是否真的收到了带合法MAC的新列表(看抓包),并核对UE侧SoR列表在TS 23.122选择逻辑中的优先级位置——SoR列表仅在自动选网模式且满足条件时才"覆盖"部分本地列表,并非无条件最高优先。
故障5:AMF透传失败导致容器丢失。 AMF若因不支持(旧版本)或Payload container处理Bug而丢弃该IE,UE收不到列表。表现为抓包里只有N11(UDM→AMF)有容器、N1(AMF→UE)没有。检查AMF版本是否支持TS 24.501 §9.11.3.51及对应Payload container type。
Q1:SoR用的K_AUSF,UE每次注册都换吗?会否导致Counter频繁重置? A:K_AUSF在每次5G主认证(5G AKA或EAP-AKA')时重新派生,所以重新认证会重置Counter(UE置0x0000)。常态下不会频繁触发——只要不重新认证,K_AUSF与Counter在整个注册周期内保持,SoR可多次增量下发。
Q2:SoR-MAC-I_AUSF和SoR-MAC-I_UE为什么FC不同(0x77 vs 0x78)? A:KDF要求派生结果与用途严格绑定。下行(网络盖章给UE)和上行(UE回执给网络)虽都用K_AUSF,但语义相反,用不同FC(0x77/0x78)隔离,避免上下行消息在KDF层面产生可关联/可伪造的交叉,是标准的"用途分离"安全工程实践。
Q3:拜访网络能不能伪造一个Counter很大的容器来"毒化"UE? A:不能造成持久危害。伪造大Counter但没有K_AUSF→算不出正确MAC→UE在第D步验签失败→不存储该Counter(§6.14.2.3明确"仅在MAC验证成功后才存储Counter")。所以UE状态机不受污染,后续HPLMN的合法列表仍被正常接受。
Q4:SoR和UPU到底什么关系? A:架构上同源、KDF同构。SoR(§6.14,A.17/A.18)推漫游优选列表,UPU(§6.15,A.19/A.20)推UE运行参数(路由指示、默认配置NSSAI等)。两者都用K_AUSF、都有16位单调Counter、都走NAS的Payload container、都有下行MAC+上行回执MAC。掌握其一即通其二。
Q5:如果UE处于手动选网模式,SoR还有效吗? A:SoR列表影响的是自动选网模式下的PLMN优先级(TS 23.122)。手动模式下用户指定网络,SoR列表不强制改写用户选择,但其安全验证(MAC/Counter)仍会执行并存储,等切回自动模式时生效。
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
