<!-- title: 5G SBA OAuth2授权安全拆解 -->
<!-- domain: security -->

# 5G SBA 服务化接口安全机制：NRF OAuth2 令牌签发与 mTLS 双向认证全链拆解

## 一、为什么 SBA 需要一套全新的安全模型

5G 核心网（5GC）相对 4G EPC 最根本的架构变化，是控制面网元之间从"点到点参考点接口（S6a/S11/S5 等）"演进为**服务化接口（Service Based Interface, SBI）**。所有网络功能（Network Function, NF）统一以 RESTful + HTTP/2 的方式对外暴露能力，并通过**网络仓储功能（NRF）**完成注册、发现与调用。

这一变化带来三个 4G 时代不存在的安全问题：

1. **网元身份消失**。在 EPC 中，S6a 是 HSS 与 MME 之间的固定管道，IPSec/隧道一拉，两端天然互信。而在 SBA 中，任意一个 NF 都可以向另一个 NF 发起 HTTP 请求，网元之间没有物理专线意义上的"身份绑定"。
2. **接口暴露面急剧扩大**。每个 NF 都是一个 HTTP 服务器，攻击面从"少数几个网关"变成"全部网元"。
3. **细粒度授权需求**。AMF 可能需要调用 UDM 的 `nudm-sdm`（签约数据），但不应该被授权调用 `nudm-ee`（事件暴露）。仅仅"认证你是合法 NF"不够，还必须"授权你只能调用某个具体服务"。

为此，TS 33.501 Section 13 专门定义了 **SBA 安全（Security aspects of the Service Based Architecture）**，它由三层防御体系构成：**传输层安全（NDS for SBA）+ NF 注册/发现认证 + OAuth2 服务级授权**。本文聚焦第三层——也是其中机制最复杂、信令交互最丰富的一层：**NRF 作为 OAuth2 授权服务器，向 NF Consumer 签发 JWT 访问令牌（Access Token）的全链流程**。

> 设计意图：3GPP 没有自己发明一套鉴权协议，而是**复用成熟的 OAuth 2.0 Client Credentials 授权模式（RFC 6749）**，并强制令牌采用 JWT（RFC 7519）格式。这样运营商可以复用现成的 PKI/Token 中间件生态，同时令牌自包含（无需每次回查 NRF），极大降低 Nnrf 接口的鉴权信令风暴。

---

## 二、SBA 三层安全体系总览

```mermaid
flowchart TB
    subgraph L3["第3层：服务级授权 Authorization"]
        O["OAuth2 Client Credentials<br/>NRF = Authorization Server<br/>JWT Access Token (Bearer)"]
    end
    subgraph L2["第2层：注册与发现认证 Authentication"]
        R["mTLS 双向认证<br/>NRF 校验 NF 证书 (TS 33.310 CA)"]
    end
    subgraph L1["第1层：传输层保护 Transport"]
        T["NDS for SBA: TLS 1.2/1.3 或 IPsec<br/>TS 33.210 / TS 33.310"]
    end
    NFc[NF Consumer] --> L1 --> L2 --> L3 --> NFp[NF Producer]
    style L3 fill:#fde2e4
    style L2 fill:#fff3bf
    style L1 fill:#d3f9d8
```

三层职责严格分工：

- **第 1 层（传输层，TS 33.501 §13 + TS 33.210 §6.2）**：保证 HTTP/2 报文在网络上机密性与完整性，防止窃听与篡改。PLMN 内部用 TLS（或经 SCP/服务通信代理转发），跨 PLMN 漫游则由 SEPP 在 N32 上做应用层映射保护（本文不展开，详见 [[sepp]]）。
- **第 2 层（认证层，TS 33.501 §13）**：NF 向 NRF 注册时通过**双向 TLS（mTLS）**证明自身身份，证书由运营商私有的 PKI（TS 33.310 网络域安全认证框架）签发。NRF 只为持有合法证书的 NF 建立信任。
- **第 3 层（授权层，TS 33.501 §13.4 + TS 29.510 §5.4）**：即便认证通过，NF Consumer 调用某个 NF Producer 的具体服务前，必须持有 NRF 签发的、scope 受限的 OAuth2 令牌。

下文重点拆解第 3 层。

---

## 三、OAuth2 全链信令时序图

下图展示一次完整的"AMF 想要读取 UDM 签约数据"的服务调用，从注册到令牌获取再到服务调用的完整 4 个阶段：

```mermaid
sequenceDiagram
    autonumber
    participant AMF as NF Consumer<br/>(AMF)
    participant NRF as NRF<br/>(Authorization Server)
    participant UDM as NF Producer<br/>(UDM)
    participant CA as Operator PKI<br/>(TS 33.310)

    Note over AMF,CA: 阶段0：建立 mTLS 信任（一次性）
    CA-->>AMF: 签发 NF 证书
    CA-->>UDM: 签发 NF 证书
    CA-->>NRF: 签发 NRF 证书

    Note over AMF,NRF: 阶段1：NF 注册 (Nnf_NFManagement_NFRegister)
    AMF->>NRF: PUT /nnrf-nfm/v1/nf-instances/{amfId}<br/>携带 NFProfile<br/>[mTLS 双向认证]
    NRF->>NRF: 校验 AMF 证书 (链→CA)<br/>存储 NFProfile
    NRF-->>AMF: 201 Created

    Note over AMF,NRF: 阶段2：NF 发现 (Nnf_NFDiscovery)
    AMF->>NRF: GET /nnrf-disc/v1/nf-instances?<br/>target-nf-type=UDM&...<br/>[mTLS]
    NRF-->>AMF: 200 OK<br/>返回 UDM 的 NFProfile (FQDN/IP, 服务列表)

    Note over AMF,NRF: 阶段3：获取 OAuth2 令牌 (Nnrf_AccessToken_Get)
    AMF->>NRF: POST /oauth2/token<br/>grant_type=client_credentials<br/>nfInstanceId=AMF, targetNfType=UDM<br/>scope=nudm-sdm<br/>requesterPlmn, targetPlmn<br/>[mTLS 客户端鉴权]
    NRF->>NRF: 构造 JWT<br/>用 NRF 私钥签名 (ES256)
    NRF-->>AMF: 200 OK<br/>{access_token:JWT, token_type:Bearer,<br/>expires_in:3600, scope}

    Note over AMF,UDM: 阶段4：携带令牌调用服务 (Nudm_SDM_Get)
    AMF->>UDM: GET /nudm-sdm/v2/{suppi}/am-data<br/>Authorization: Bearer {JWT}<br/>[mTLS]
    UDM->>UDM: 验签(NRF公钥)→iss→aud→exp→scope
    UDM-->>AMF: 200 OK<br/>AccessAndMobilitySubscriptionData
```

关键点：**令牌的获取（阶段 3）与服务的调用（阶段 4）是解耦的**。AMF 拿到令牌后会本地缓存（通常到 `expires_in` 前 30~60 秒），后续多次调用 UDM 都复用同一个令牌，直到过期再刷新。这正是 OAuth2 设计相对于"每次调用都回查 NRF"的核心价值。

---

## 四、AccessTokenReq 关键 IE 拆解（阶段 3）

阶段 3 的请求是 OAuth2 标准 `client_credentials` 模式，但 3GPP 在 RFC 6749 的基础上**扩展了大量 NF 专有字段**，用于 NRF 做细粒度授权决策。下面是 TS 29.510 中 `AccessTokenReq` 的结构：

```mermaid
flowchart LR
    REQ["AccessTokenReq<br/>POST /oauth2/token<br/>Content-Type: x-www-form-urlencoded"]:::root
    REQ --> G["grant_type<br/>=client_credentials"]:::req
    REQ --> NFI["nfInstanceId<br/>发起方NF实例ID"]:::req
    REQ --> SC["scope<br/>请求的服务范围"]:::req
    REQ --> NT["targetNfType<br/>目标NF类型"]
    REQ --> NFT["nfType<br/>发起方NF类型"]
    REQ --> RPM["requesterPlmn<br/>发起方PLMN"]
    REQ --> TPM["targetPlmn<br/>目标PLMN"]
    REQ --> RSN["requesterSnssaiList<br/>发起方切片"]
    REQ --> TSN["targetSnssaiList<br/>目标切片"]
    REQ --> TNFI["targetNfInstanceId<br/>精确目标实例"]
    REQ --> TSET["targetNfSetId<br/>目标NF集合"]
    classDef req fill:#ffe066,stroke:#333
    classDef root fill:#a5d8ff,stroke:#333
```

下表对每个 IE 进行说明：

| IE 字段 | 是否必选 | 含义与设计意图 | 示例值 |
|---------|---------|---------------|--------|
| `grant_type` | 必选 | 固定为 `client_credentials`。SBA 中 NF 调用 NF 是"机器对机器"，没有用户参与，故只能用此模式，不能用授权码模式。 | `client_credentials` |
| `nfInstanceId` | 必选 | 发起方 NF 的全局唯一实例 ID（UUID），对应阶段 1 注册时的 `nfInstanceId`，是 JWT 中 `sub` 的来源。 | `550e8400-e29b-...` |
| `scope` | 必选 | 请求授权的服务名集合，格式 `<service-name> [target-nf-type] [requester-nf-type]`，是后续授权裁决的核心依据。 | `nudm-sdm` |
| `targetNfType` | 可选 | 目标 NF 类型（UDM/PCF/UDR…），用于限定令牌受众，落入 JWT 的 `aud`。 | `UDM` |
| `nfType` | 可选 | 发起方 NF 类型，便于 NRF 按角色裁剪授权（例如限制 RAN 侧 NF 不能调用计费服务）。 | `AMF` |
| `requesterPlmn` / `targetPlmn` | 可选 | 漫游场景关键字段。当跨 PLMN 调用经 SEPP 时，NRF 依据 PLMN 颁发定向令牌，防止令牌被跨运营商滥用。 | `46000` / `46001` |
| `requesterSnssaiList` / `targetSnssaiList` | 可选 | 网络切片维度授权，使令牌仅在特定切片内有效，实现切片级隔离。 | `01-000001` |
| `targetNfInstanceId` / `targetNfSetId` | 可选 | 将令牌绑定到**特定实例或 NF 集合**，缩小令牌泄露后的爆炸半径。 | set-id |

> **设计意图**：RFC 6749 的原始 `client_credentials` 只有 `grant_type`、`scope`、客户端凭证。3GPP 通过加入 `targetNfType`、`requesterPlmn`、`requesterSnssaiList` 等，把一个"粗粒度的应用令牌"升级为"**绑定到目标网元+运营商+切片的多维令牌**"，从而在 JWT 的 claim 里把后续服务调用所需的全部上下文一次性固化，使 Producer 端的本地校验成为可能（无需回调 NRF），这是 5GC 能支撑百万级 SBI 调用/秒的关键。

---

## 五、AccessTokenRsp 与 JWT 令牌结构（TS 29.510 Annex C）

NRF 返回的 `AccessTokenRsp` 非常简洁（符合 RFC 6749）：

```
{
  "access_token": "<JWT 字符串>",
  "token_type":   "Bearer",
  "expires_in":   3600,
  "scope":        "nudm-sdm"
}
```

真正有技术含量的是 `access_token` 内部的 **JWT（JSON Web Token）**。TS 29.510 Annex C 规定了其 claim 结构，由 NRF 用自己的私钥签名（推荐 ES256 / RS256）：

```mermaid
flowchart TB
    JWT["JWT = Header.Payload.Signature"]:::jwt
    JWT --> H["Header<br/>{alg:ES256, typ:JWT}"]
    JWT --> P["Payload (Claims)"]:::claim
    JWT --> S["Signature<br/>ES256(Header.Payload, NRF私钥)"]:::sig
    P --> C1["iss: NRF 的 FQDN"]
    P --> C2["sub: 发起方 NF Instance ID"]
    P --> C3["aud: 目标 NF 类型/实例"]
    P --> C4["exp: 过期时间(Unix秒)"]
    P --> C5["iat: 签发时间"]
    P --> C6["scope: 实际授予范围<br/>≤请求scope"]
    P --> C7["jti: 令牌唯一ID<br/>(防重放/可吊销)"]
    P --> C8["nfInstanceId / targetNfInstanceId<br/>+ 自定义 claim"]
    classDef jwt fill:#b197fc
    classDef claim fill:#ffc9c9
    classDef sig fill:#bac8ff
```

JWT 自包含的好处：**UDM 在阶段 4 校验令牌时，只需要 NRF 的公钥证书（一次性获取并缓存），就能在本地完成验签 + 过期检查 + scope 检查**，全过程不产生到 NRF 的任何反向信令。对比 Diameter 时代每次鉴权都要回 HSS 查询，这是一个数量级的性能提升。

---

## 六、令牌生命周期状态机

一个 access token 从签发到被废弃，经历如下状态流转。理解这张图是排错的基础：

```mermaid
stateDiagram-v2
    [*] --> Issuing: POST /oauth2/token
    Issuing --> Valid: 200 OK (exp=T+3600s)
    Valid --> InUse: 携带 Bearer 调用 Producer
    InUse --> Valid: 本地缓存复用
    Valid --> Refreshing: 距 exp < 提前量(如60s)
    Refreshing --> Valid: 申请新令牌
    Valid --> Expired: 当前时间 ≥ exp
    Expired --> [*]: Producer 返回 401<br/>触发重新获取
    InUse --> Revoked: NRF 吊销(jti 入黑名单)
    Revoked --> [*]: Producer 校验失败
    note right of Valid
        Producer 端 4 项校验:
        1. 验签(NRF公钥)
        2. iss==NRF
        3. aud 匹配本 NF 类型
        4. scope 覆盖被调服务
    end note
```

注意 3GPP 的实现中**通常不支持令牌主动吊销（revocation endpoint 可选）**，主要依赖短有效期（默认 1 小时）自然过期。这也是为什么 `expires_in` 一般设置为 3600 秒而非 24 小时——以时间换安全。

---

## 七、传输层安全：NDS for SBA（mTLS + 证书链）

阶段 1~4 的每一次 HTTP/2 报文，都必须承载在受保护通道上。TS 33.501 §13 与 TS 33.210 §6.2 共同定义了 **NDS for SBA**：

| 维度 | PLMN 内部（Intra-PLMN） | 跨 PLMN 漫游（Inter-PLMN） |
|------|------------------------|---------------------------|
| 保护位置 | NF 之间 / NF 与 SCP 之间 | 经由 SEPP 在 N32 接口 |
| 机制 | **mTLS 双向认证**（TLS 1.2/1.3） | TLS VPN 互信 + SEPP 应用层映射（PRINS） |
| 证书来源 | 运营商私有 CA（TS 33.310） | 运营商间互信 CA / 测试证书 |
| 对 OAuth2 的影响 | mTLS 同时充当 OAuth2 的**客户端鉴权**（无需在 body 传 client_secret） | 令牌中 `requesterPlmn`/`targetPlmn` 生效 |
| 关键规范 | TS 33.210 §6.2, TS 33.310 | TS 33.501 §13.1.2, TS 33.512（NDS for N32） |

> **关键细节**：在 `client_credentials` 模式下，RFC 6749 要求客户端证明身份（通常用 `client_secret`）。但在 SBA 中，由于底层已是 mTLS，NRF 直接把 **mTLS 客户端证书中的身份**当作 OAuth2 客户端身份，**无需在 `/oauth2/token` 请求里明文传 `client_secret`**。这就是为什么前文 `AccessTokenReq` 里没有 `client_secret` 字段——它由传输层承担。这是 3GPP 对标准 OAuth2 的一个安全增强。

---

## 八、实战：抓包识别与故障排查

### 8.1 抓包识别（Wireshark / TShark）

由于 SBI 跑在 HTTP/2 + TLS 上，要在 NF 之间抓到明文，**必须在 NF 进程内启用 SSLKEYLOGFILE**（开源 free5GC、OAI 均支持），否则只能看到 TLS 加密流量。识别 OAuth2 流量的过滤条件：

```
# 令牌申请请求（阶段3）
http2.headers.method == "POST" && http2.headers.path contains "/oauth2/token"
http2.headers.content_type == "application/x-www-form-urlencoded"

# 令牌响应
http2.headers.content_type == "application/json" && frame contains "access_token"

# 服务调用（阶段4）—— 关键是 Authorization: Bearer
http2.headers.authorization contains "Bearer"
```

一个典型故障场景的抓包特征：**阶段 3 成功返回 JWT，但阶段 4 Producer 回 `401 Unauthorized`**——这几乎 100% 是令牌校验失败（见下文）。

### 8.2 常见故障点与排查思路

| 症状 | 可能根因 | 排查方向 |
|------|---------|---------|
| `POST /oauth2/token` 返回 `401` | mTLS 客户端证书无效/过期/CA 不被 NRF 信任 | 检查 NF 证书有效期、CA 链、NRF 信任库（TS 33.310） |
| 返回 `400` + `invalid_scope` | 请求的 `scope` 与 NF 角色不匹配，或服务名拼写错误 | 核对 TS 29.5xx 中该服务的标准 scope 名（如 `nudm-sdm`，不是 `udm-sdm`） |
| Producer 返回 `401` | JWT 验签失败（NRF 公钥未更新）/ `exp` 已过 / `iss` 不匹配 | 在 Producer 抓包解码 JWT Header+Payload；确认 Producer 缓存的 NRF 公钥与签发密钥配对 |
| Producer 返回 `403` | 认证通过但**授权不通过**：`scope` 未覆盖被调服务，或 `aud` 与本 NF 类型不符 | 检查 JWT 的 `scope`、`aud` claim；是否 AMF 拿了 `nudm-sdm` 的令牌却去调 `nudm-ueau` |
| 漫游场景间歇性 403 | `requesterPlmn`/`targetPlmn` 未携带或 SEPP 透传后被改写 | 确认漫游双方 PLMN ID 配置一致，SEPP 应用层策略 |
## 九、与其他方案的对比

| 维度 | OAuth2 Access Token（SBA, 本方案） | 传统 Diameter 鉴权（EPC） | API Key / 静态密钥 |
|------|-----------------------------------|------------------------|-------------------|
| 标准基础 | RFC 6749 + RFC 7519（JWT） | RFC 6733 | 厂商私有 |
| 粒度 | 服务级（scope）+ 网元级（aud）+ 切片级（S-NSSAI） | 接口级 | 仅"是否合法" |
| 鉴权位置 | Producer 本地（JWT 自包含） | 需回查 HSS/ Diameter 代理 | Producer 本地比对 |
| 过期/吊销 | 短时过期 + 可选 revocation | 长连接 + 会话 | 无 |
| 横向扩展 | 天然无状态，易 Scale-out | 有状态，Diameter 代理压力大 | 无状态 |
| 适用场景 | 大规模云原生 NF 间调用 | 4G 网元间 | 简单内部系统 |

可以看出，SBA OAuth2 是**为云原生、服务网格化、高并发**量身定制的方案，这也是它在 Rel-15 引入后迅速成为 5GC NF 间默认安全机制的原因。

---

## 十、设计哲学小结

回过头看整个 SBA 安全体系，可以提炼出三条贯穿始终的设计哲学：

1. **分层与解耦**：传输安全（mTLS）、身份认证（注册/发现）、服务授权（OAuth2）三层各司其职，任一层被攻破都不会直接导致全盘失守。
2. **复用而非发明**：3GPP 选择 OAuth2 + JWT + TLS 这些成熟 IETF 标准，而非自研协议，降低了实现成本和互操作风险，也让安全社区的长尾研究红利直接惠及 5GC。
3. **自包含换可扩展**：JWT 令牌把授权决策所需上下文全部封装，换取 Producer 端的**无状态本地校验**，这是支撑 5GC 控制面云原生弹性扩缩容的安全基石。

对协议开发工程师而言，理解 SBA 安全不是孤立的"加个证书"，而是一套**端到端的、与架构同呼吸的信任传递体系**——这正是它区别于传统网络安全、也是本文聚焦拆解它的价值所在。

---

## 常见问题

**Q1: 为什么 3GPP 用 `client_credentials` 模式，而不是授权码（authorization code）模式？**
A: 授权码模式是为"有用户参与的第三方应用授权"设计的（如用微信登录第三方 App）。而 SBA 中是 NF 调用 NF，**没有用户参与**，发起方就是机器本身，使用 `client_credentials` 模式可以让 NF 直接用自身身份（mTLS 证书）换取令牌，流程最简、最契合 M2M 场景。

**Q2: 既然底层已有 mTLS，为什么还要再加一层 OAuth2 令牌？这不是冗余吗？**
A: 不冗余，二者解决不同问题。mTLS 解决"**你是谁**"（认证），OAuth2 解决"**你能做什么**"（授权）。mTLS 只能证明 AMF 是合法 NF，但无法表达"AMF 可以调 `nudm-sdm` 但不能调 `nudm-ee`"这种服务级、参数级细粒度策略。令牌的 `scope` + `aud` + 切片 claim 才是实现最小权限原则的关键。

**Q3: JWT 令牌过期后，正在进行的批量服务调用会怎样？**
A: Producer 校验到 `exp` 已过会返回 `401 Unauthorized`。健壮的 Consumer 实现会**捕获 401 → 自动重新执行 `Nnrf_AccessToken_Get` → 用新令牌重试**，对上层业务透明。因此实践中建议 Consumer 在本地令牌剩余有效期低于阈值（如 60s）时就主动预刷新，避免请求期内的 401 抖动。

**Q4: 令牌丢失或泄露怎么办？SBA 支持令牌吊销吗？**
A: TS 29.510 中 revocation 是**可选**实现，多数商用部署依赖短有效期（默认 3600s）自然过期来控制风险，而非主动吊销。如果需要更强保障，可结合 `jti`（令牌唯一 ID）+ NRF 黑名单，或通过收紧 `aud`/`targetNfInstanceId` 把令牌绑定到特定实例，缩小泄露爆炸半径。

**Q5: 引入了 SCP（服务通信代理）后，令牌该由谁申请？**
A: TS 29.500 定义了多种通信模型。在 **Model C（委托授权）** 下，Consumer 不自己申请令牌，而是把请求发给 SCP，由 SCP 代为向 NRF 申请令牌并附加到请求中转发给 Producer。这种模式下 Consumer 完全无感，但调试时需在 SCP 侧抓 OAuth2 信令。

---

## 参考来源

1. [3GPP TS 33.501 V18.10.0 — Security architecture and procedures for 5G System](https://www.etsi.org/deliver/etsi_ts/133500_133599/133501/18.10.00_60/ts_133501v181000p.pdf) — Section 13（SBA 安全）、§13.4（NF 服务访问授权）、§13.1.2（TLS VPN 互信，引用 TS 33.210 §6.2）
2. [3GPP TS 29.510 — Network Function Repository Services; Stage 3](https://www.3gpp.org/ftp/Specs/archive/29_series/29.510/) — Section 5.4（Nnrf_AccessToken 服务）、Annex C（JWT 访问令牌 claim 结构）
3. [Ericsson — Security for 5G SBA: updates since Release 16](https://www.ericsson.com/en/blog/2024/2/5g-sba-security-release-16-updates) — 对 SCP、SEPP、OAuth2 演进的厂商视角解读
4. [free5GC — Authentication Mechanism in NRF: What Is OAuth](https://free5gc.org/blog/20230802/20230802/) — 开源实现中 `/oauth2/token` 信令与抓包细节
5. [RFC 6749 — The OAuth 2.0 Authorization Framework](https://rfc.blacklabs.team/rfc6749.html) + [RFC 7519 — JSON Web Token (JWT)] — Client Credentials 授权模式与 JWT 编码规范

---

> 本文由「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)
