RFC8489-STUN
0. 学习参考
RFC5389 中文翻译 中文RFC RFC文档 RFC翻译 RFC中文版
RFC 5389:NAT 的会话遍历实用程序 (STUN) --- RFC 5389: Session Traversal Utilities for NAT (STUN)
1. RFC 3489的演变
自 RFC 3489 发布以来的经验发现,经典的 STUN 根本无法很好地工作,无法成为可部署的解决方案。通过传统 STUN 学习的地址和端口有时可用于与对等体通信,有时则不能。Classic STUN 无法发现它是否实际上有效,并且在不起作用的情况下它不提供任何补救措施。此外,发现经典的 STUN 用于 NAT 类型分类的算法是错误的,因为许多 NAT 不能完全适应那里定义的类型。
Classic STUN 还存在一个安全漏洞——攻击者可以在某些拓扑和约束下向客户端提供不正确的映射地址,而这从根本上无法通过任何加密手段解决。尽管该规范仍然存在此问题,但现在通过使用使用 STUN 的更完整的解决方案来缓解这些攻击。
2. STUN 业务概况
STUN 是一种客户端 - 服务器协议,核心功能是帮助端点穿越 NAT,实现地址发现、连接性检查和 NAT 绑定维持。以下是其操作概述的核心内容:
1. 协议架构与组件
-
实体角色:
- STUN 代理(Agent):分为客户端和服务器,客户端发送请求 / 指示并接收响应,服务器处理请求并返回响应。
- 网络组件:包括私有网络、NAT 设备和公共互联网,客户端通过 NAT 与服务器通信,服务器位于公共网络侧。
-
事务类型:
- 请求 / 响应事务:客户端发送请求(如获取反射地址),服务器返回响应,通过 96 位事务 ID 关联请求与响应,确保唯一性和防重放攻击。
- 指示事务:单向消息(如保活信号),不期待响应,用于维持 NAT 绑定活性。
2. STUN包 Binding 方法与反射地址获取
-
核心功能:
- 通过 Binding 请求 / 响应 确定客户端在 NAT 后的公网地址(反射地址)。客户端发送请求,经 NAT 后服务器获取其公网 IP 和端口,通过响应中的 XOR-MAPPED-ADDRESS 返回。
- 反射地址用途:用于 ICE 等 NAT 穿越方案,使端点能在公共网络中建立连接。
-
流程细节:
- 客户端发送 Binding 请求,源地址被 NAT 转换为公网地址。
- 服务器接收请求,记录源地址(反射地址),填入响应属性并返回。
- 客户端解析响应,获取自身在公网的映射地址。
3. stun 多协议复用与区分机制
当 STUN 与其他协议(如 RTP、SIP)复用同一传输通道时,通过以下方式区分消息:
- 固定头部特征:STUN 头部前两位为 0,Cookie 为固定值。
- FINGERPRINT 属性:可选 CRC-32 校验值,用于精确区分 STUN 与非 STUN 数据包。
4. stun 可选机制与安全扩展
认证机制:支持 短期凭证(带外协商用户名 / 密码)和 长期凭证(Digest 挑战 / 响应),通过 MESSAGE-INTEGRITY 属性确保消息完整性。
DNS 发现:通过 STUN URI(如 stun://)和 SRV 记录查找服务器地址,支持自动配置。
3. STUN 消息结构
3.1 消息整体架构与编码规则
- 所有 STUN 消息必须以 20 字节的标头开头,后跟零个或多个属性。STUN 标头包含 STUN 消息类型、magic cookie、交易 ID 和消息长度。
- 每条 STUN 消息的最高有效 2 位必须为零,多路复用时,这可用于将 STUN 数据包与其他协议区分开来。
- 标头的 STUN 固定部分后面是零个或多个属性。每个属性都经过 TLV(Type-Length-Value) 编码。
3.2 固定头部
- 二进制编码:采用网络字节序(大端序),遵循 [RFC 0791] 规范,数值常量默认十进制。
- 固定头部 + 属性扩展:消息由 20 字节固定头部 和 可选属性字段 组成,属性采用 TLV(Type-Length-Value)格式,总长度需对齐 4 字节边界。
STUN字段 | 长度 | 描述 |
---|---|---|
MSG TYPE | 2 字节 | 高 2 位为 0(区分其他协议),剩余 14 位分为: - 12 位 方法(Method):如 Binding(0x0001) - 2 位 类(Class):0b00 = 请求,0b01 = 指示,0b10 = 成功响应,0b11 = 错误响应 |
MSG length | 2 字节 | 不包含头部的消息体长度(字节数),需为 4 的倍数(通过填充确保)。 |
Cookie | 4 字节 | 固定值 0x2112A442 ,用于区分 STUN 包与其他协议,兼容 RFC 5389 扩展检测。 |
transcation ID | 12 字节 | 96 位随机数,唯一标识事务: - 请求 / 响应事务中由客户端生成,服务器回复携带 - 指示事务中由发送方生成,用于调试和防攻击 |
示例:
- Binding 请求:类 = 0b00,方法 = 0x0001 → 消息类型 = 0x0001
- Binding 成功响应:类 = 0b10,方法 = 0x0001 → 消息类型 = 0x0101
3.3 属性
格式:每个属性由 2 字节类型、2 字节长度、可变长度值 组成,值需填充至 4 字节边界(填充字节置 0)。
分类:
- 必须理解属性(0x0000-0x7FFF):若不支持则无法处理消息,如
MAPPED-ADDRESS
、ERROR-CODE
。 - 可选理解属性(0x8000-0xFFFF):不支持时可忽略,如
SOFTWARE
、ALTERNATE-SERVER
。
Type | 属性名 | 含义 |
---|---|---|
0x0001 | MAPPED-ADDRESS | 客户端在服务器端看到的 NAT 后的反射地址,包含 IP 地址和端口。用于帮助客户端发现自己的公共 IP 地址和端口。仅用于兼容 RFC 3489 客户端,新协议推荐使用 XOR-MAPPED-ADDRESS 防 NAT ALG 篡改。 |
0x0006 | USERNAME | 用于消息完整性检查和认证过程的用户名,标识消息完整性验证中使用的用户名,该值为可变长度的 UTF-8 编码序列,且需经过OpaqueString 处理(基于 RFC 8265,非 SASLprep),用于短期 / 长期凭证的用户名标识。 |
0x0008 | MESSAGE-INTEGRITY | 包含 STUN 消息的 HMAC-SHA1 哈希值(20 字节),用于确保消息在传输过程中未被篡改,保证消息的完整性和真实性。 |
0x0009 | ERROR-CODE | 用于错误响应消息,包含一个 300 到 699 范围内的数字错误代码,以及一个 UTF-8 编码的文本短语,用于描述错误的具体信息。 |
0x000A | UNKNOWN-ATTRIBUTES | 当服务器收到包含其不识别属性的 STUN 消息时,会在错误码为 420 的错误响应中使用该属性列出这些未知属性的类型。 |
0x0014 | REALM | 可出现在请求和响应消息中,包含符合特定语法的文本,用于长期凭据认证。它是一个 UTF-8 编码序列,长度少于 128 个字符,且经过 SASLprep 处理,出现该字段表示使用长期凭据认证方式。 |
0x0015 | NONCE | 由服务器生成的一个可变长度的不透明值,用于防止重放攻击。客户端在后续请求中需要包含相同的 NONCE 值,服务器通过检查 NONCE 值确保消息的新鲜性和唯一性。需 UTF-8 编码且经 SASLprep 处理。 |
0x0020 | XOR-MAPPED-ADDRESS | 与 MAPPED-ADDRESS 作用相同,不同点是 IP 地址经过了异或(XOR)处理。解决 ALG 篡改地址和端口的问题。 |
0x0024 | PRIORITY | 在 ICE(交互式连接建立)过程中,用于指示候选地址的优先级。客户端会收集多个候选地址,每个地址都有对应的优先级,服务器或对端可根据该优先级决定优先使用哪个候选地址建立连接。RFC 8445 ICE 扩展定义。 |
0x0025 | USE-CANDIDATE | 用于通知对端立即使用指定的 ICE 候选地址对进行连接,跳过部分候选地址筛选和验证过程,加速连接的建立。RFC 8445 ICE 扩展定义。 |
0x001C | MESSAGE-INTEGRITY-SHA256 | 与 MESSAGE-INTEGRITY 类似,但使用 SHA256 算法计算消息的 HMAC 哈希值,提供更高的安全性,用于保证消息的完整性。 |
0x001D | PASSWORD-ALGORITHM | 用于指定认证过程中所使用的密码算法,告知对端采用何种加密算法对密码进行处理和验证。 |
0x001E | USERHASH | 对用户名进行哈希处理后的值,用于在不直接传输明文用户名的情况下进行用户标识和认证,增强了用户信息的安全性。 |
0x8002 | PASSWORD-ALGORITHMS | 列出服务器支持的所有密码算法,客户端可以根据这些信息选择合适的算法进行认证。 |
0x8003 | ALTERNATE-DOMAIN | 提供一个备用的域名,用于在主域名不可用时作为替代,可能用于引导客户端到备用的服务或资源。 |
0x8022 | SOFTWARE | 携带生成该 STUN 消息的软件或设备的相关信息,如软件名称、版本号等,有助于网络故障排查和统计分析。 |
0x8023 | ALTERNATE-SERVER | 提供备用的 STUN 或 TURN 服务器地址,当主服务器不可用时,客户端可以尝试连接这些备用服务器。 |
0x8028 | FINGERPRINT | 对消息计算的 CRC-32 值,用于快速验证消息完整性。接收方重新计算 CRC-32 值并与该属性值比较,若一致则消息未被篡改。 |
0x8029 | ICE-CONTROLLED | 在 ICE 连接建立过程中,标识一个端点处于受控(Controlled)角色,该端点需遵循控制者端点的决策来建立连接。RFC 8445 ICE 扩展定义。 |
0x802A | ICE-CONTROLLING | 在 ICE 连接建立过程中,标识一个端点处于控制(Controlling)角色,该端点负责协调和决定使用哪个候选地址对来建立连接。RFC 8445 ICE 扩展定义。 |
0x8000-0xFFFF | 可选的理解属性 | 类型值在 0x8000 和 0xFFFF 之间的属性是可选的理解属性,这意味着这些属性如果 STUN 代理不理解它们,则可以忽略它们。 |
3.4 STUN消息处理与边界检测
- 头部校验:接收方需验证:
- 前 2 位为 0,Cookie 为
0x2112A442
,消息长度合理。 - 方法是否支持,类是否匹配方法(如指示类不可用于某些扩展方法)。
- 前 2 位为 0,Cookie 为
- 属性解析:
- 按顺序处理属性,重复属性仅处理首个(除非规范另有说明)。
- 必须理解属性缺失或无法解析时,返回
420 Unknown Attribute
错误。
- 事务关联:通过事务 ID 匹配请求与响应,指示消息无需响应但需校验事务 ID 有效性。
3.5 举例
Binding 请求(无认证)
- 头部:消息类型 = 0x0001(请求),长度 = 0,魔术 Cookie=0x2112A442,事务 ID = 随机 96 位值。
- 属性:无(或含
SOFTWARE
等可选属性)。
Binding 成功响应
- 头部:消息类型 = 0x0101(成功响应),长度 = 属性总长度。
- 属性:必须包含
XOR-MAPPED-ADDRESS
(含客户端公网地址和端口)。
4. 基本协议程序
消息构造与传输规则(6.1-6.2)
"客户端应以RTO(“重新传输超时”)的间隔开始重新传输STUN请求消息,每次重新传输后加倍。RTO是对往返时间(RTT)的估计,按照RFC 2988[RFC2988]中的描述计算,但有两个例外。首先,RTO的初始值应该是可配置的(而不是RFC 2988中建议的3 s),并且应该大于500 ms。这种“应该”的例外情况是,当使用其他机制来推导拥塞阈值时(如ICE中为固定速率流定义的机制),或者在已知网络容量的非互联网环境中使用STUN。在固定线路接入链路中,建议使用500 ms的值。其次,RTO的值不应四舍五入到最接近的秒。相反,应保持1 ms的精度。与TCP一样,建议使用Karn算法[KARN87]。当应用于STUN时,这意味着RTT估计值不应根据导致请求重新传输的STUN事务计算。"
1. 传输协议支持:
- UDP/DTLS-over-UDP: 不可靠传输,客户端需重传(初始 RTO≥500ms,指数退避,默认重传 7 次);消息大小≤576 字节(IPv4)或 1280 字节(IPv6)。
- TCP/TLS-over-TCP:可靠传输,依赖 TCP 层重传,客户端超时默认 39.5s;支持多事务复用(同一服务器≤10 个并发),TLS 需验证证书并禁用弱密码套件。
- 协议复用:若与其他协议复用 TCP 连接,需通过成帧协议分割消息,知名端口(3478)的 STUN 服务无需成帧。
2. 消息接收与处理流程(6.3)
通用校验步骤:
- 头部验证:检查魔术 Cookie、消息长度、事务 ID 匹配及方法有效性,若启用
FINGERPRINT
需校验 CRC 值。 - 属性解析:忽略未知可选属性,若遇未知必须属性,返回
420 Unknown Attribute
错误并列出属性类型。
3. 按消息类处理逻辑:
- 请求(Request):验证通过后生成响应:成功响应含
XOR-MAPPED-ADDRESS
(反射地址),错误响应含ERROR-CODE
(如 400/401);UDP 重传请求需确保响应一致性(如缓存事务 ID)。 - 指示(Indication):无需响应,直接处理消息(如刷新 NAT 绑定),含未知必须属性则丢弃。
- 响应(Response):客户端校验
MESSAGE-INTEGRITY
,失败则按协议重传(UDP)或终止(TCP)。
4. 错误处理与重试机制
错误码分类:
- 3xx(重定向):如
300 Try Alternate
,客户端需切换至ALTERNATE-SERVER
属性指定的备用服务器。 - 4xx(客户端错误):如
401 Unauthenticated
(认证失败)、438 Stale Nonce
(凭证过期),需客户端重试并携带新凭证。 - 5xx(服务器错误):如
500 Server Error
,客户端可重试,但重传次数≤4 次。
5. FINGERPRINT 机制
FINGERPRINT 机制是 STUN 的可选扩展,用于在 多协议复用同一传输地址(如 UDP 端口或 TCP 连接)时,准确区分 STUN 消息与其他协议的数据包,避免协议解析混淆。例如,当 STUN 与 RTP、SIP 等协议共享端口时,可通过该机制确保 STUN 消息被正确识别和处理。FINGERPRINT 机制不向后兼容 RFC 3489,并且不能在需要此类兼容性的环境中使用。
技术实现
属性结构:FINGERPRINT 属性为可选理解属性(类型 0x8028
),需作为 STUN 消息的最后一个属性,确保校验覆盖整个消息内容。属性值为 CRC-32 校验值,计算方式为:
- 对消息中除 FINGERPRINT 属性本身外的所有字节计算 CRC-32
- CRC-32 生成多项式为
将多项式的各项系数转换为二进制(仅保留最高位至最低位的非零位),其对应的 32 位二进制掩码 为:
100000100110000010001101101100111
(共 32 位,首位为 1)。) - 将计算结果与固定值
0x5354554E
("STUN" 的 ASCII 码异或值)进行异或运算,得到最终属性值。
校验流程:
- 接收方收到消息后,先剥离 FINGERPRINT 属性,重新计算剩余内容的 CRC-32,并异或
0x5354554E
。 - 将计算结果与属性值对比,若不一致则判定为非 STUN 消息或被篡改的消息,直接丢弃。
6. DNS Discovery of a Server 机制
1. 核心功能与用途
DNS 发现机制是 STUN 的可选扩展,用于帮助客户端通过 DNS 协议动态获取 STUN 服务器的 IP 地址和端口号,避免硬编码服务器地址,提升协议的灵活性和可维护性。适用于客户端无法预先知晓服务器地址的场景(如公共互联网环境)。
2. STUN URI 方案
URI 格式:
stun://
:用于普通 UDP/TCP 连接的 STUN 服务器(非加密)。stuns://
:用于 TLS-over-TCP 或 DTLS-over-UDP 连接的加密 STUN 服务器。
语法规则:
- 示例:
stun:stun.example.com:3478
或stuns:stun-secure.example.com:5349
。- 若 URI 包含 IP 地址(如
stun:192.168.1.1:3478
),客户端直接连接;若包含域名(如stun.example.com
),需通过 DNS 解析。
3. DNS 解析流程
3.1 SRV 记录优先
客户端首先查询 DNS SRV 记录,格式为:
<scheme>
:stun
或stuns
(对应 URI 方案)。<protocol>
:udp
或tcp
(传输协议)。- 示例:查询
_stun._udp.example.com
获得 UDP 协议的 STUN 服务器地址和端口。- SRV 记录返回优先级(Priority)、权重(Weight)和目标地址(Target),客户端按优先级和权重选择服务器。
_<scheme>._<protocol>.example.com
3.2 直接查询 A/AAAA 记录
若 SRV 记录不存在,客户端查询域名的 A 记录(IPv4) 或 AAAA 记录(IPv6),使用默认端口:
- UDP/TCP:3478。
- TLS/DTLS:5349。
双栈客户端需同时查询 A 和 AAAA 记录,尝试所有地址。
4. 传输协议与端口
默认端口:
协议类型 | 普通连接(stun://) | 加密连接(stuns://) |
---|---|---|
UDP/TCP | 3478 | 不适用 |
TLS-over-TCP | 不适用 | 5349 |
DTLS-over-UDP | 不适用 | 5349 |
端口复用:服务器可在同一端口支持多种协议(如 UDP 和 DTLS 共用 5349 端口),通过初始消息类型区分。
7. 加密认证与消息完整性机制
1. 核心目标与机制概述
STUN 定义两种认证与消息完整性机制,用于防范中间人攻击、消息篡改和重放攻击,确保通信双方身份可信及数据完整。
- 适用场景:
- 短期凭证:临时会话(如 ICE 连接)。
- 长期凭证:固定用户身份(如企业认证)。
- 关键属性:
USERNAME
(用户名)、MESSAGE-INTEGRITY
(HMAC 哈希)、NONCE
(防重放随机值)。
2. 短期凭证机制(Short-Term Credential Mechanism)
2.1 核心流程与机制
-
带外密钥协商
- 客户端与服务器通过非 STUN 协议的安全渠道(例如 SIP 信令、WebRTC 信令)提前共享短期有效的用户名(
USERNAME
)和密码(PASSWORD
)。 - 凭证时效性:凭证仅在特定时间段或会话周期内有效(如媒体会话期间),超时后自动失效,降低泄露风险。
- 客户端与服务器通过非 STUN 协议的安全渠道(例如 SIP 信令、WebRTC 信令)提前共享短期有效的用户名(
-
消息完整性校验
- HMAC 算法:使用HMAC-SHA1或HMAC-SHA256算法计算消息的完整性校验值,具体取决于协商的算法。
- 属性携带:
- 客户端请求中必须包含:
USERNAME
属性(UTF-8 编码的用户名,经 OpaqueString 处理)。MESSAGE-INTEGRITY
(HMAC-SHA1 结果,20 字节)或MESSAGE-INTEGRITY-SHA256
(HMAC-SHA256 结果,≥16 字节且为 4 的倍数)。
- 服务器响应中需包含对应的完整性属性(但不包含
USERNAME
,避免明文传输)。
- 客户端请求中必须包含:
-
密钥生成规则
- 密钥直接由密码的 UTF-8 字节序列生成:
key=OpaqueString(password) - 无需复杂的挑战响应流程,直接通过预共享密钥计算 HMAC 值,提升认证效率。
- 密钥直接由密码的 UTF-8 字节序列生成:
2.1 关键处理逻辑
客户端发送请求: 构造 STUN 消息时,将USERNAME
和完整性属性附加到消息中。例如,在 Binding 请求中,客户端通过带外获取的用户名和密码生成 HMAC 值,填入MESSAGE-INTEGRITY-SHA256
属性。
服务器验证流程:
- 提取
USERNAME
和完整性属性,验证用户名是否在有效期内。- 如果消息不同时包含消息完整性和用户名属性:
- 如果消息是请求,则服务器必须以错误响应拒绝该请求。此响应必须使用错误代码400(错误请求)。
- 如果消息是一个指示,则代理必须以静默方式放弃该指示。
- 如果消息不同时包含消息完整性和用户名属性:
- 使用相同的密码和算法重新计算 HMAC 值,与消息中的属性值对比:
- 一致:认证通过,代理将继续处理请求或指示。服务器生成的任何响应都必须包含MESSAGE-INTEGRITY属性,该属性使用用于验证请求的密码进行计算。响应不能包含USERNAME属性。
- 不一致:返回
401 Unauthenticated
错误,拒绝请求。 - 如果消息是一个指示,则代理必须以静默方式放弃该指示。
客户端收到答复
客户端在响应中查找MESSAGE-INTEGRITY属性。如果存在,客户端将使用其用于请求的相同密码,按照第15.4节中的定义计算响应上的消息完整性。如果结果值与MESSAGE-INTEGRITY属性的内容匹配,则认为响应已通过身份验证。如果值不匹配,或者缺少消息完整性,则必须丢弃响应,就像从未收到响应一样。这意味着重新传输(如果适用)将继续。
3. 长期凭证机制
长期凭证机制(Long-Term Credential Mechanism)是一种基于预共享密钥的认证方式,适用于需要长期固定身份验证的场景(如企业用户、服务订阅者)。其核心是通过挑战 / 响应流程和密码算法协商,确保通信双方身份可信及消息完整性,同时防范重放攻击和算法降级攻击。
1. 凭证来源与特性
- 预共享凭证: 客户端与服务器通过带内或带外渠道预先配置用户名(
USERNAME
)和密码(PASSWORD
),凭证长期有效(如用户注册时生成),直至用户主动修改或服务终止。 - 适用场景: 企业网络、需要用户登录的服务(如 VoIP 运营商),或需长期维护信任关系的通信场景。
2. 认证流程:挑战 / 响应模式
第一步:未认证请求(首次交互)
- 客户端发送不含认证属性的 STUN 请求(如 Binding 请求)。
- 服务器返回 **
401 Unauthenticated
错误响应 **,附带:REALM
属性:认证域(如example.com
),指示用户使用的凭证范围。NONCE
属性:服务器生成的防重放随机值,包含安全特征位(如支持的密码算法标识)。
第二步:携带凭证的二次请求
客户端收到挑战后,生成认证信息:
- 用户名处理:
- 明文
USERNAME
或哈希值USERHASH
(SHA-256(USERNAME:REALM)
,避免明文传输)。
- 明文
- 密钥生成:
- 根据协商的密码算法(如 MD5、SHA-256),生成 HMAC 密钥:
- 完整性校验:
- 使用密钥计算消息的
MESSAGE-INTEGRITY
或MESSAGE-INTEGRITY-SHA256
,覆盖请求头部、REALM
、NONCE
等属性。
- 使用密钥计算消息的
客户端重新发送请求,包含USERNAME
/USERHASH
、REALM
、NONCE
及完整性属性。
第三步:服务器验证
服务器校验:
NONCE
有效性:检查是否为近期生成,未被篡改(通过安全特征位匹配协商的算法)。- HMAC 一致性:使用相同算法和密钥重新计算 HMAC,与请求中的完整性属性对比。
验证通过:返回成功响应;失败:返回401
或438 Stale Nonce
(NONCE 过期,需重试)。
3. 长期凭证 安全增强机制
(1) 防重放与防降级攻击
-
NONCE 的安全特征位:
-
NONCE 前缀包含
obMatJos2
+ 安全特征位编码(如Bit 0
表示支持密码算法协商),防止中间人删除强算法属性(如强制使用 MD5)。 -
若客户端发现响应中
PASSWORD-ALGORITHMS
与 NONCE 特征位矛盾,终止会话。
-
(2) 密码算法协商
-
算法列表: 服务器通过
PASSWORD-ALGORITHMS
属性声明支持的算法(如MD5
、SHA-256
),客户端通过PASSWORD-ALGORITHM
选择其一。 -
推荐算法:
-
优先使用
SHA-256
,因其抗碰撞性优于 MD5;MD5 仅用于兼容旧系统。
-
(3) 用户名匿名化
-
使用
USERHASH
替代USERNAME
:避免在网络中传输明文用户名,降低身份泄露风险。
4. 消息完整性计算示例
假设使用 SHA-256 算法:
服务器收到后,用相同密钥和算法重新计算,验证是否一致。
5. 与短期凭证机制的对比
特性 | 长期凭证机制 | 短期凭证机制 |
---|---|---|
凭证生命周期 | 长期有效(用户级) | 短期有效(会话级) |
认证流程 | 挑战 / 响应(需 2 次消息往返) | 直接携带凭证(1 次往返) |
安全强度 | 高(支持算法协商 + 防降级) | 中(依赖带外渠道安全性) |
适用场景 | 企业认证、固定用户 | 临时会话、实时通信 |
总结
长期凭证机制通过预共享密钥和挑战响应流程,为需要长期信任关系的场景提供了可靠的认证方案。REALM、USERNAME、 NONC(领域 - 身份 - 会话)其核心优势在于支持密码算法协商、防重放攻击和用户名匿名化,同时通过 NONCE 的安全特征位抵御中间人攻击。尽管流程较短期凭证复杂,但适用于对安全性要求较高的企业级部署,是 STUN 协议在身份认证领域的重要扩展。
涉及相关知识
Karn 算法
Karn 算法是用于 TCP(传输控制协议)中往返时间(RTT,Round-Trip Time)测量和估计的一种算法。它主要用于解决在 TCP 重传时如何准确估计 RTT 的问题。
Karn 算法的核心思想是:在数据包重传时,不使用重传后接收到的 ACK 来更新 RTT 估计。具体来说,当数据包被重传后,接收到的 ACK 不能用于测量 RTT,因为无法确定该 ACK 是对原始传输还是重传的响应。
Karn 算法的具体步骤
-
初始传输:当一个数据包首次传输时,记录发送时间,并启动超时计时器。
-
接收 ACK:如果在超时时间内接收到 ACK,使用该 ACK 来更新 RTT 估计。
-
超时重传:如果超时时间到达且未接收到 ACK,重传数据包,并重置超时计时器。
-
处理重传后的 ACK:
-
当接收到 ACK 时,如果该 ACK 确认的是重传的数据包,则不使用该 ACK 来更新 RTT 估计。
-
如果该 ACK 确认的是原始传输的数据包,则可以使用该 ACK 来更新 RTT 估计。
-
Karn 算法的优点
-
提高 RTT 估计的准确性:避免了因重传导致的 RTT 样本不准确的问题,从而提高了 RTT 估计的准确性。
-
稳定性:通过避免使用重传后的 ACK 来更新 RTT 估计,减少了因网络抖动或丢包导致的 RTT 估计波动。
Karn 算法的限制
-
无法处理所有情况:在某些情况下,例如网络中存在重复 ACK 或部分确认时,Karn 算法可能无法完全避免 RTT 估计的不准确。
-
依赖于其他机制:Karn 算法通常与其他机制(如 duplicated ACK 检测)结合使用,以进一步提高 RTT 估计的准确性。
Karn 算法的总结
Karn 算法通过避免使用重传后的 ACK 来更新 RTT 估计,提高了 RTT 估计的准确性。这对于 TCP 的拥塞控制和流量控制非常重要,因为它可以更准确地反映网络的实际延迟情况,从而更好地适应网络条件的变化。
HMAC
在 RFC 8489 中,HMAC(Hash-Based Message Authentication Code)用于实现 消息完整性校验 和 身份认证,确保 STUN 消息在传输中未被篡改,并验证通信方身份。以下是文档中关于 HMAC 计算的核心内容:
1. 核心用途与算法支持
用途:
- 验证消息完整性:确保消息在传输过程中未被中间人篡改。
- 认证通信方:通过共享密钥(密码)证明发送方身份。
支持的算法:
- HMAC-SHA1(20 字节,用于
MESSAGE-INTEGRITY
属性)。 - HMAC-SHA256(≥16 字节,用于
MESSAGE-INTEGRITY-SHA256
属性)。 - 长期凭证机制中支持 MD5 等算法(通过
PASSWORD-ALGORITHM
属性协商)。
特性 | SHA1 | SHA256 |
---|---|---|
哈希长度 | 160 位(20 字节) | 256 位(32 字节) |
抗碰撞性 | 已被证明存在碰撞风险,不安全 | 尚未被攻破,符合现代安全标准 |
文档推荐性 | 仅用于兼容旧版本 | 优先使用,尤其是敏感场景 |
防降级攻击 | 可被中间人强制使用(需额外防护) | 通过Nonce 安全特征位抵制降级攻击 |
2. 短期凭证机制中的 HMAC 计算
2.1 密钥生成
密钥来源: 密钥为客户端与服务器通过带外协商的 密码(Password),经 UTF-8 编码后直接使用,不进行额外处理:key=OpaqueString(password),OpaqueString
指直接使用字节序列,不进行 Unicode 规范化(RFC 8265)。
2.2 输入数据范围
计算对象:除 MESSAGE-INTEGRITY
/MESSAGE-INTEGRITY-SHA256
属性本身外的整个 STUN 消息。
步骤:
- 构造消息时,先预留完整性属性位置(长度字段设为 0,值设为 dummy)。
- 计算 HMAC 值,覆盖头部、其他属性及预留字段。
- 将计算得到的 HMAC 值填入属性,并更新消息长度字段。
2.3 示例公式
若使用 HMAC-SHA256:
结果需至少 16 字节,且为 4 的倍数(如 32 字节)。
3. 长期凭证机制中的 HMAC 计算
3.1 密钥生成(以 MD5 为例)
步骤:
- 将 用户名(Username)、域(Realm)、密码(Password) 拼接为字符串:
username:realm:password
。 - 计算拼接字符串的 MD5 哈希,生成 16 字节密钥:
算法协商: 通过 PASSWORD-ALGORITHMS
(服务器支持列表)和 PASSWORD-ALGORITHM
(客户端选择)指定算法(如 SHA-256)。
3.2 输入数据与计算逻辑
与短期凭证类似,但需包含 NONCE
、REALM
等认证相关属性。
防重放机制: 服务器生成的 NONCE
包含安全特征位,确保 HMAC 计算与当前会话绑定,防止重放攻击。
4. 关键处理规则
4.1 消息长度调整
计算 HMAC 前,需将消息长度字段临时设置为 包含完整性属性占位符的长度,计算完成后再更新为实际值。示例:
- 原始消息长度为 L(不含完整性属性),占位符长度为 4(类型 + 长度字段),临时长度设为 L+4,最终填入 L+4+N(N 为 HMAC 值长度)。
4.2 响应中的 HMAC 回显
服务器响应必须包含与请求匹配的完整性属性(如请求使用 MESSAGE-INTEGRITY-SHA256
,响应也需包含该属性)。
响应中 不包含 USERNAME
,避免明文传输用户身份信息。
5. 安全与兼容性
防降级攻击: 通过 NONCE
中的安全特征位(如 Password algorithms
位)标识支持的算法,防止中间人强制使用弱算法(如 MD5)。
兼容性:
- 旧版本客户端可能仅支持 HMAC-SHA1,需通过协议协商兼容。
- 新版本推荐使用 HMAC-SHA256,满足更高安全要求。