<!-- title: 5G SBI服务化接口OAuth2令牌安全拆解 -->
<!-- domain: security -->

# 5G SBI 服务化接口安全：NRF OAuth2/JWT 令牌与 mTLS 双层防护全链拆解

> 子域轮转：2026 年第 177 天，本轮聚焦 **security（网络安全）**。本文专门拆解 5GC 服务化架构（SBA）中 NF 之间的认证与授权机制——这是一条与 UE 侧主认证完全独立、却同样决定整网安全基线的"NF 间安全链"。

## 一、为什么 SBI 需要一套独立的安全机制

5G 核心网（5GC）彻底转向**服务化架构（Service-Based Architecture, SBA）**：所有网络功能（NF）不再用点对点专用接口（如 4G 的 S6a/S11），而是通过统一的 HTTP/2 RESTful 服务化接口（SBI）相互调用，并由 NRF（Network Repository Function）充当"服务注册中心 + 授权服务器"。

这套架构带来了一个 4G 没有的新安全命题：**任意两个 NF 之间都可能发生服务调用，而且调用链经常跨越多个中间节点（负载均衡器、消息代理、跨 PLMN 的 SEPP）**。如果只靠传输层的 TLS，会出现两个致命问题：

1. **TLS 是"逐跳（hop-by-hop）"的**：当报文经过代理或 SEPP 转发时，TLS 会话在中间节点上被解密再重新加密，攻击者或被攻陷的中间节点可以篡改业务报文体。
2. **TLS 只能证明"管道"可信，不能表达"业务授权"**：TLS 的证书只能回答"你是谁"，却无法回答"你有没有权限调用这个 NF 的这个具体服务操作、访问这个 SUPI 的数据"。

因此 3GPP 在 TS 33.501 第 13 章为 SBI 设计了**双层安全架构**：传输层做相互认证与机密性/完整性保护，消息层做细粒度授权与端到端完整性。理解这两层如何分工、如何衔接，是 5GC 安全研发与运维的基础。

## 二、双层安全架构总览

```mermaid
flowchart TB
    subgraph T["传输层安全（TS 33.501 §13.2）"]
        T1["mTLS 双向认证<br/>基于证书（NDS/IP）"]
        T2["逐跳机密性 + 完整性<br/>HTTP/2 over TLS 1.2/1.3"]
        T3["信任范围：单个安全域 / 单跳"]
    end
    subgraph M["消息层安全（TS 33.501 §13.3）"]
        M1["OAuth2 授权<br/>NRF 作为授权服务器"]
        M2["JWT/JWS 签名<br/>端到端完整性 + 不可否认"]
        M3["信任范围：NF-A ↔ NF-B 端到端"]
    end
    UE["NF Service Consumer<br/>（如 AMF/SMF）"] --> T --> M --> PROD["NF Service Producer<br/>（如 UDM/PCF）"]
    style T fill:#e8f0fe,stroke:#1a73e8
    style M fill:#fce8e6,stroke:#d93025
```

两层各司其职，核心分工如下：

| 维度 | 传输层（Transport） | 消息层（Message） |
|------|-------------------|------------------|
| 标准出处 | TS 33.501 §13.2 | TS 33.501 §13.3 / TS 29.510 §5.4 |
| 主要机制 | mTLS（双向证书）+ NDS/IP | OAuth2 令牌 + JWT/JWS 签名 |
| 解决的问题 | "双方是谁" + 管道加密 | "能否调用此服务" + 端到端完整性 |
| 保护粒度 | 整个 TCP/HTTP 连接 | 单条 SBI 请求/响应报文体 |
| 保护范围 | 逐跳（hop-by-hop） | 端到端（NF 源到 NF 宿） |
| 中间节点影响 | 被代理即被解密 | 签名贯穿全程，中间节点无法伪造 |

设计意图非常清晰：**TLS 保证"路"是安全的，OAuth2/JWT 保证"信"是可信的**。即使报文穿过 SEPP、负载均衡器等中间设施，只要 JWT 签名验证通过，目的 NF 就能确信报文确实来自声称的源 NF 且未被篡改。

## 三、传输层：mTLS 与 NDS/IP

SBI 默认承载在 HTTP/2 over TLS 之上。在同一个安全域（Security Domain）内，NF 与 NRF、NF 与 NF 之间通过**相互 TLS 认证（mTLS）**建立加密通道：双方都要出示并由对方校验 X.509 证书。

这一层的信任根来自 **NDS/IP（Network Domain Security for IP，TS 33.310）**：每个安全域部署一个或多个证书签发体系（通常为运营商私有的 CA），跨安全域时则在边界节点（如 SEPP）之间通过 IPsec 或专用的网络域安全策略打通。值得注意的是，NRF 自己也支持在 `NfProfile` 中携带 `nfServiceList`、`plmnList`、`sNssais` 等属性，便于在发现阶段就做域内/域间过滤，但**身份认证本身仍然由 mTLS 完成，而不是靠这些元数据**。

mTLS 解决了"管道加密"问题，但它管不到"这条 HTTP 报文里授权了哪个服务"。这就引出了核心的消息层机制——OAuth2。

## 四、消息层核心：NRF 作为 OAuth2 授权服务器

### 4.1 模型：OAuth2 在 SBI 中的角色映射

TS 33.501 §13.3.1 明确规定：**NF 与 NRF 之间的认证与授权应使用 OAuth2**。3GPP 把标准 OAuth2（RFC 6749）的角色做了如下映射：

- **资源服务器（Resource Server）** = NF 服务生产者（Service Producer，如 UDM、PCF、UDR）
- **客户端（Client）** = NF 服务消费者（Service Consumer，如 AMF、SMF）
- **授权服务器（Authorization Server）** = NRF（具体是 `Nnrf_AccessToken` 服务）
- **资源（Resource）** = 某个 NF 服务（如 `nudm-sdm`、`npcf-smpolicycontrol`）

消费者要调用生产者的某个服务前，先向 NRF 申请一个 **OAuth2 Access Token**，再带着这个令牌向生产者发起服务请求；生产者验证令牌后才提供服务。NRF 因此成为全网统一的**信任代理与授权中心**。

### 4.2 完整信令时序图

下图以"AMF 调用 UDM 的 `Nudm_SDM` 服务（获取签约数据）"为例，展示完整的 OAuth2 令牌获取与服务调用链：

```mermaid
sequenceDiagram
    autonumber
    participant C as AMF<br/>(NF Consumer)
    participant N as NRF<br/>(授权服务器)
    participant P as UDM<br/>(NF Producer)

    Note over C,N: 步骤①发现（可选：已缓存则跳过）
    C->>N: GET /nnrf-disc/v1/nf-instances<br/>(target-nf-type=UDM, requester-nf-type=AMF)
    N-->>C: 200 OK (UDM 实例信息 + 服务列表)

    Note over C,N: 步骤② mTLS + OAuth2 令牌请求
    C->>N: POST /oauth2/token<br/>grant_type=client_credentials<br/>nfInstanceId={AMF id}<br/>nfType=AMF, targetNfType=UDM<br/>targetNfInstanceId={UDM id}<br/>scope="nudm-sdm"
    N->>N: 校验 mTLS 证书 + 校验 scope 授权
    N-->>C: 200 OK<br/>access_token = JWS(AccessTokenClaims)<br/>expires_in=3600

    Note over C,P: 步骤③ 带 Bearer 令牌调用服务
    C->>P: GET /nudm-sdm/v2/{suPI}/am-data<br/>Authorization: Bearer {access_token}
    P->>P: 验证 JWS 签名(用NRF公钥)<br/>校验 aud==自身ID, scope匹配, exp未过期
    P-->>C: 200 OK (签约数据)
    Note right of P: 令牌缓存于 Producer 用于后续校验加速
```

需要强调一个常被忽略的设计细节：**步骤②的令牌请求是"消费者 → NRF"，而非"消费者 → 生产者"**。令牌由 NRF 签发，但由生产者验证。这意味着生产者必须信任 NRF 的签名（持有 NRF 公钥），而消费者只需信任 NRF 这一个授权点即可对接全网任意生产者——这就是"信任集中、对接解耦"的核心收益。

### 4.3 Access Token 请求/响应的 IE 结构

令牌的请求与响应由 TS 29.510 §5.4.2.2 定义，对应 OpenAPI 中的 `AccessTokenReq` 与 `AccessTokenRsp`。其字段结构如下：

```mermaid
flowchart LR
    REQ["AccessTokenReq<br/>(POST /oauth2/token)"]:::req --> R1["grant_type<br/>= client_credentials (必填)"]
    REQ --> R2["nfInstanceId<br/>消费者NF实例ID (必填)"]
    REQ --> R3["scope<br/>申请的服务范围 (必填)<br/>如 nudm-sdm"]
    REQ --> R4["nfType / targetNfType<br/>消费者/生产者类型"]
    REQ --> R5["targetNfInstanceId<br/>目的NF实例ID"]
    REQ --> R6["requesterPlmn / targetPlmn<br/>源/目的 PLMN"]
    RSP["AccessTokenRsp"]:::rsp --> S1["access_token<br/>JWS 紧凑序列化签名"]
    RSP --> S2["token_type<br/>= Bearer"]
    RSP --> S3["expires_in<br/>有效期(秒)"]
    classDef req fill:#e8f0fe,stroke:#1a73e8;
    classDef rsp fill:#fce8e6,stroke:#d93025;
```

| IE 参数 | 必填 | 含义 | 安全作用 |
|--------|:---:|------|---------|
| `grant_type` | 是 | 固定 `client_credentials`，即客户端凭证模式 | 声明授权模式，无需用户参与 |
| `nfInstanceId` | 是 | 发起方 NF 实例 UUID | 令牌主体（sub/client_id）来源 |
| `scope` | 是 | 申请的 NF 服务名（空格分隔可多项） | **最关键的授权依据**，限定可调用服务 |
| `targetNfInstanceId` | 否 | 目的 NF 实例 ID | 收窄令牌受众，防止令牌被转用于其他实例 |
| `nfType` / `targetNfType` | 否 | 源/目的 NF 类型 | 便于 NRF 做策略校验 |
| `requesterPlmn` / `targetPlmn` | 否 | 源/目的 PLMN 标识 | 漫游场景下区分本网与拜访网 |
| `access_token` | 是 | JWS 紧凑序列化的签名 JSON | 实际的授权凭证，放入 `Authorization` 头 |
| `token_type` | 是 | 固定 `Bearer` | 声明令牌使用方式 |
| `expires_in` | 否 | 有效期（秒） | 控制令牌生命周期，默认常见 3600s |

`grant_type` 取 `client_credentials` 是经过深思熟虑的选择：SBI 是**机器对机器（M2M）**调用，不存在"终端用户同意"环节，因此采用客户端凭证模式——消费者 NF 用自己的身份（mTLS 证书）直接换取令牌，绕开了授权码（authorization code）那套面向人类用户的交互流程。这既符合 OAuth2 语义，又契合 5GC 全自动的网内通信场景。

### 4.4 Access Token 的 JWT Claims 结构

`access_token` 并非随机字符串，而是一个**经 JWS（JSON Web Signature）签名后的 JSON 对象**，其载荷（payload）即 `AccessTokenClaims`。解码后的结构如下：

```mermaid
flowchart TB
    J["JWS = Header.Signature.Payload<br/>签名算法: RS256 / ES256"]:::jwt
    J --> C1["iss (issuer)<br/>签发者 = NRF 实例ID"]
    J --> C2["sub (subject)<br/>消费者 NF 实例ID"]
    J --> C3["aud (audience)<br/>生产者 NF 实例ID/类型"]
    J --> C4["exp (expiration)<br/>过期时间戳"]
    J --> C5["iat (issued at)<br/>签发时间戳"]
    J --> C6["scope<br/>授权的服务范围"]
    J --> C7["client_id<br/>消费者 NF 实例ID"]
    J --> C8["jti (JWT ID)<br/>令牌唯一标识(防重放)"]
    classDef jwt fill:#fef7e0,stroke:#f9ab00;
```

几个 claim 的安全意义值得逐条点明：

- **`iss` + 签名**：生产者用 NRF 公钥验签，确信令牌确由本网 NRF 签发，无法伪造。
- **`aud`（受众）**：令牌绑定到特定生产者实例，即使令牌泄露也无法挪用到其他 NF，把爆炸半径降到最小。
- **`scope`**：生产者据此判断"你确实被授权调用 `nudm-sdm`，但无权调 `nudm-ueau`（鉴权服务）"，实现服务粒度的最小权限。
- **`exp` + `iat`**：限制令牌有效期，过期后生产者直接拒绝，迫使消费者周期性重新申请。
- **`jti`**：令牌唯一编号，配合生产者侧缓存可识别重放，防止令牌被截获后重复使用。

## 五、令牌生命周期：状态转换

OAuth2 令牌并非永久有效，其状态机如下。理解这套转换对排查"间歇性 401"至关重要：

```mermaid
stateDiagram-v2
    [*] --> 未获取: NF 启动/首次调用
    未获取 --> 申请中: POST /oauth2/token
    申请中 --> 有效: 200 OK (含 expires_in)
    申请中 --> 未获取: 400/401 (证书/scope 错误)
    有效 --> 有效: 命中本地缓存<br/>直接复用(剩余>阈值)
    有效 --> 申请中: 接近过期/收到401<br/>主动刷新
    有效 --> 失效: 到达 exp
    有效 --> 撤销: NRF 侧吊销(如NF注销)
    失效 --> 申请中: 重新申请
    撤销 --> 未获取: 清除本地缓存
    note right of 有效
        生产者也会缓存令牌→
        调用结果，加速校验
    end note
```

实践中，消费者 NF 通常**本地缓存令牌并在剩余有效期低于阈值（如 10%）时提前刷新**，避免每次服务调用都回溯 NRF 造成风暴；生产者 NF 也会缓存"令牌→校验结果"映射以加速验签。`expires_in` 的取值是性能与安全的权衡：过短增加 NRF 信令压力，过长放大泄露后的风险窗口。

## 六、与 SEPP/N32 的边界关系（易混淆点）

很多工程师会把"SBI 消息层安全"与"SEPP 跨域 N32 安全"混为一谈，二者其实分属不同层级：

| 对比维度 | SBI OAuth2/JWT（§13.3） | SEPP N32（§13.4 / TS 33.501） |
|---------|------------------------|------------------------------|
| 适用场景 | 同一 PLMN 内 NF 间 | 跨 PLMN 漫游（hPLMN ↔ vPLMN） |
| 信任锚 | 本网 NRF | 双方 SEPP 协商（N32-c/N32-f） |
| 保护对象 | SBI 业务报文体 | 跨域 N32 信令（含敏感字段加密） |
| 签名/加密 | JWT 签名（完整性为主） | N32-f 端到端 + 应用层加密 |
| 是否被中间节点解密 | 否（端到端 JWT 贯穿） | SEPP 间有 MSRP/PRINS 等处理 |

关键认知：**当漫游 NF 间发生 SBI 调用时，OAuth2/JWT 与 SEPP N32 是叠加生效的**——SEPP 在网络域边界做传输保护与敏感字段重写，而 JWT 依然在两端 NF 之间端到端成立，SEPP 无法伪造 vPLMN AMF 的令牌来冒充它。这正是双层架构在跨域场景下的价值。

## 七、抓包识别：如何在 Wireshark 里认出这条链

在 5GC 抓包时，识别 OAuth2 令牌链非常直观：

1. **令牌申请**：`POST /oauth2/token`，`Content-Type: application/x-www-form-urlencoded`，body 形如
   `grant_type=client_credentials&nfInstanceId=xxx&scope=nudm-sdm&targetNfType=UDM`。
2. **令牌响应**：`200 OK`，`Cache-Control: no-store`、`Pragma: no-cache`（强制不缓存，安全要求），body 是 JSON `{"access_token":"eyJhbGciOi...", "token_type":"Bearer", "expires_in":3600}`。
3. **服务调用**：随后 NF Consumer 的业务请求 HTTP 头携带 `Authorization: Bearer eyJhbGciOi...`。
4. **JWT 解码**：`access_token` 以 `eyJ` 开头（base64url 的 `{"alg":...}` 头），可在 jwt.io 等工具拆出三段，payload 中可见 `iss/sub/aud/scope/exp`。

典型故障点与排错思路：

- **401 Unauthorized**：先查 mTLS 证书是否过期/不受信任（域名、SAN、CA 链），再查 `scope` 是否在生产者授权清单内、`aud` 是否匹配生产者实例 ID、`exp` 是否已过期。
- **令牌频繁刷新（NRF 压力高）**：检查消费者侧缓存逻辑，确认是否忽略 `expires_in` 每次都申请；核对提前刷新阈值是否设得过激进。
- **403 Forbidden**：通常不是认证问题，而是 `scope` 与请求的具体操作不匹配（如令牌含 `nudm-sdm` 却调用了 `nudm-ueau`）。
- **跨 PLMN 调用失败**：确认 `requesterPlmn/targetPlmn` 是否正确填写、是否经 SEPP 正确路由、NRF 是否对拜访网 NF 做了漫游授权策略。
## 常见问题

**Q1: 既然已经有 mTLS，为什么还要 OAuth2/JWT 这一层？**
A: mTLS 是逐跳（hop-by-hop）的，只能证明连接两端身份并加密管道，无法表达"对这个具体服务/数据有没有授权"，也无法在报文经过代理/SEPP 时保证端到端完整性。OAuth2/JWT 是端到端的，弥补了授权粒度与跨中间节点的完整性两个缺口。二者是叠加而非替代关系。

**Q2: `scope` 和 `aud` 分别限制什么？**
A: `aud`（audience）限制**令牌能给哪个 NF 实例用**（绑定目的方，防挪用）；`scope` 限制**令牌能调用哪个服务**（绑定业务能力，防越权）。一个绑定了 UDM 实例的 `nudm-sdm` 令牌，既不能拿去调 PCF，也不能拿去调 UDM 的 `nudm-ueau`。

**Q3: 生产者如何验证 JWT 签名？需要每次都连 NRF 吗？**
A: 不需要。生产者本地预置/定期获取 NRF 的公钥（JWK Set），验签在本地完成；只有首次或公钥轮换时才需与 NRF 同步公钥。生产者还会缓存"令牌→校验结果"以加速重复请求的判定。

**Q4: 漫游场景下，vPLMN 的 AMF 能否用本网 NRF 签发的令牌调 hPLMN 的 UDM？**
A: 视运营商策略而定。通常跨 PLMN 调用经 SEPP（N32）完成传输保护与路由，OAuth2 授权策略可允许或拒绝跨域令牌（取决于 hPLMN 是否信任 vPLMN NRF 及其 scope 策略）。关键在于 hPLMN UDM 侧的 `aud` 与公钥信任配置。

**Q5: 令牌泄露会有什么后果？**
A: 由于令牌绑定了 `aud`（特定生产者实例）和 `exp`（短有效期），且生产者侧可基于 `jti` 防重放，泄露令牌的爆炸半径被显著限制——只能用于指定生产者、指定 scope、且很快过期。配合 mTLS，攻击者即便拿到令牌也无法建立可信连接，实现了深度防御。

## 参考来源

1. [3GPP TS 33.501 V18.10.0 — Security architecture and procedures for the 5G system](https://www.etsi.org/deliver/etsi_ts/133500_133599/133501/18.10.00_60/ts_133501v181000p.pdf) — §13 Security of the SBA（13.2 传输层、13.3 消息层、13.4 网络域与跨 PLMN）
2. [3GPP TS 29.510 — Network Function Repository Services; Stage 3](https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=3345) — §5.4 Nnrf_AccessToken 服务（令牌请求/响应、§5.4.2.2.3 多 NRF 中间令牌请求）
3. [3GPP TS29510_Nnrf_AccessToken.yaml (OpenAPI)](https://www.3gpp.org/ftp/Specs/archive/OpenAPI/Rel-15/TS29510_Nnrf_AccessToken.yaml) — AccessTokenReq/AccessTokenRsp 字段与 JWS 紧凑序列化定义
4. [free5GC — Introduction to OAuth2 Procedure](https://free5gc.org/blog/20231115/free5GC_OAuth2_Procedure/) — 基于 TS 33.501 §13.3.1 的 NF-NRF 授权流程实现解读
5. [free5GC — Authentication Mechanism in NRF: What Is OAuth?](https://free5gc.org/blog/20230802/20230802/) — OAuth2 在 SBI 中的角色映射与图解

---
> 本文由「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 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
