跳到主要内容

10. 认证和消息完整性机制 (Authentication and Message-Integrity Mechanisms)

本节定义客户端和服务器可用于在 STUN 中提供认证和消息完整性的两种机制: 短期凭据机制和长期凭据机制. 这两种机制都是可选的, 每种用法都必须说明是否以及何时使用这些机制. 因此, 客户端和服务器都可以根据适用的用法知道应遵循哪种机制 (如果有). 例如, 公共 Internet 上支持 ICE 的 STUN 服务器不会使用认证, 而支持连通性检查的代理中的 STUN 服务器功能会使用短期凭据机制. Section 3 给出了这两种机制的概述.

每种机制都规定了使用该机制所需的附加处理, 扩展了 Section 7 中规定的处理. 附加处理发生在三个不同位置: 构造消息时, 接收消息并完成基本检查后立即进行的处理, 以及错误响应的详细处理.

10.1. 短期凭据机制 (Short-Term Credential Mechanism)

短期凭据机制假定, 在 STUN 事务之前, 客户端和服务器已经使用某种其他协议交换了由用户名和密码组成的凭据. 该凭据具有时间限制. 时间限制由具体用法定义.

例如, 在 ICE 用法 [MMUSIC-ICE] 中, 两个端点使用带外信令协商用户名和密码, 该用户名和密码在媒体会话持续期间适用.

该凭据用于在每个请求以及许多响应中形成消息完整性检查. 它不像长期机制那样使用质询和响应; 因此, 重放攻击通过凭据的时间受限特性来防止.

10.1.1. 构造请求或指示 (Forming a Request or Indication)

对于请求或指示消息, 代理必须在消息中包含 USERNAME 和 MESSAGE-INTEGRITY 属性. MESSAGE-INTEGRITY 属性的 HMAC 按 Section 15.4 所述计算. 注意, 密码绝不会包含在请求或指示中.

10.1.2. 接收请求或指示 (Receiving a Request or Indication)

代理完成消息的基本处理后, 按指定顺序执行以下检查:

  • 如果消息没有同时包含 MESSAGE-INTEGRITY 和 USERNAME 属性:

    • 如果消息是请求, 服务器必须使用错误响应拒绝该请求. 此响应必须使用错误码 400 (Bad Request).

    • 如果消息是指示, 代理必须静默丢弃该指示.

  • 如果 USERNAME 不包含服务器当前有效的用户名值:

    • 如果消息是请求, 服务器必须使用错误响应拒绝该请求. 此响应必须使用错误码 401 (Unauthorized).

    • 如果消息是指示, 代理必须静默丢弃该指示.

  • 使用与该用户名关联的密码, 按 Section 15.4 所述计算消息完整性值. 如果所得值与 MESSAGE-INTEGRITY 属性的内容不匹配:

    • 如果消息是请求, 服务器必须使用错误响应拒绝该请求. 此响应必须使用错误码 401 (Unauthorized).

    • 如果消息是指示, 代理必须静默丢弃该指示.

如果这些检查通过, 代理继续处理请求或指示. 服务器生成的任何响应必须包含 MESSAGE-INTEGRITY 属性, 该属性使用用于认证请求的密码计算. 响应不得包含 USERNAME 属性.

如果任一检查失败, 服务器不得在错误响应中包含 MESSAGE-INTEGRITY 或 USERNAME 属性. 这是因为在这些失败场景下, 服务器无法确定计算 MESSAGE-INTEGRITY 所需的共享密钥.

10.1.3. 接收响应 (Receiving a Response)

客户端在响应中查找 MESSAGE-INTEGRITY 属性. 如果存在, 客户端使用请求所用的同一密码, 按 Section 15.4 中定义的方式计算该响应的消息完整性. 如果所得值与 MESSAGE-INTEGRITY 属性的内容匹配, 则认为响应已通过认证. 如果值不匹配, 或者 MESSAGE-INTEGRITY 不存在, 响应必须被丢弃, 就好像从未收到过一样. 这意味着在适用时, 重传会继续进行.

10.2. 长期凭据机制 (Long-Term Credential Mechanism)

长期凭据机制依赖长期凭据, 其形式为客户端和服务器共享的用户名和密码. 该凭据被视为长期凭据, 因为它假定是为用户配置的, 并会一直有效, 直到该用户不再是系统订户或凭据被更改. 这基本上就是提供给用户的传统 "log-in" 用户名和密码.

由于这些用户名和密码预期会长期有效, 重放防护以摘要质询的形式提供. 在此机制中, 客户端最初发送请求时不提供任何凭据或完整性检查. 服务器拒绝此请求, 并向用户提供 realm (用于指导用户或代理选择用户名和密码) 以及 nonce. nonce 提供重放保护. 它是服务器选择的 cookie, 并以某种方式编码, 用来指示其有效期或其有效的客户端身份. 客户端重试该请求, 这次包含其用户名和 realm, 并回显服务器提供的 nonce. 客户端还包含消息完整性, 该完整性为包括 nonce 在内的整个请求提供 HMAC. 服务器验证 nonce 并检查消息完整性. 如果二者匹配, 则请求通过认证. 如果 nonce 不再有效, 则认为它是 "stale", 服务器拒绝该请求并提供新的 nonce.

在发往同一服务器的后续请求中, 客户端重用先前使用的 nonce, username, realm 和 password. 这样, 后续请求不会被拒绝, 直到服务器使 nonce 失效; 此时拒绝响应会向客户端提供新的 nonce.

注意, 长期凭据机制不能用于保护指示, 因为指示无法被质询. 使用指示的用法必须要么使用短期凭据机制, 要么对这些指示省略认证和消息完整性.

由于长期凭据机制容易受到离线字典攻击, 部署应该使用难以猜测的密码. 如果凭据不是由用户输入, 而是在设备配置期间放置到客户端设备上, 则密码应该至少具有 128 bit 随机性. 如果凭据由用户输入, 则用户应该遵循当前关于密码结构的最佳实践.

10.2.1. 构造请求 (Forming a Request)

构造请求时有两种情况. 第一种情况是客户端向服务器 (由其 IP 地址和端口标识) 发送的第一个请求. 第二种情况是客户端在先前的请求/响应事务成功完成后提交后续请求. 作为 401 或 438 错误响应结果而构造请求的处理见 Section 10.2.3, 它不被视为 "subsequent request", 因此不使用 Section 10.2.1.2 中描述的规则.

10.2.1.1. 第一个请求 (First Request)

如果客户端尚未与服务器完成一次成功的请求/响应事务 (如果使用 Section 9 的 DNS 过程, 则由 hostname 标识; 否则由 IP 地址标识), 则它应该省略 USERNAME, MESSAGE-INTEGRITY, REALM 和 NONCE 属性. 换言之, 最初的请求发送时就像未应用认证或消息完整性一样.

10.2.1.2. 后续请求 (Subsequent Requests)

一旦请求/响应事务成功完成, 服务器就已经向客户端提供了 realm 和 nonce, 客户端也已经选择了用于认证的 username 和 password. 客户端应该缓存 username, password, realm 和 nonce, 以便后续与服务器通信. 当客户端发送后续请求时, 它应该使用这些缓存值包含 USERNAME, REALM 和 NONCE 属性. 它应该包含 MESSAGE-INTEGRITY 属性, 该属性使用缓存的密码按 Section 15.4 所述计算.

10.2.2. 接收请求 (Receiving a Request)

服务器完成请求的基本处理后, 按指定顺序执行以下检查:

  • 如果消息不包含 MESSAGE-INTEGRITY 属性, 服务器必须生成错误码为 401 (Unauthorized) 的错误响应. 此响应必须包含 REALM 值. 推荐将 REALM 值设为 STUN 服务器提供者的域名. 响应必须包含由服务器选择的 NONCE. 响应不应该包含 USERNAME 或 MESSAGE-INTEGRITY 属性.

  • 如果消息包含 MESSAGE-INTEGRITY 属性, 但缺少 USERNAME, REALM 或 NONCE 属性, 服务器必须生成错误码为 400 (Bad Request) 的错误响应. 此响应不应该包含 USERNAME, NONCE, REALM 或 MESSAGE-INTEGRITY 属性.

  • 如果 NONCE 不再有效, 服务器必须生成错误码为 438 (Stale Nonce) 的错误响应. 此响应必须包含 NONCE 和 REALM 属性, 并且不应该包含 USERNAME 或 MESSAGE-INTEGRITY 属性. 服务器可以使 nonce 失效以提供额外安全性. 指导意见见 [RFC2617] 的 Section 4.3.

  • 如果 USERNAME 属性中的 username 无效, 服务器必须生成错误码为 401 (Unauthorized) 的错误响应. 此响应必须包含 REALM 值. 推荐将 REALM 值设为 STUN 服务器提供者的域名. 响应必须包含由服务器选择的 NONCE. 响应不应该包含 USERNAME 或 MESSAGE-INTEGRITY 属性.

  • 使用与 USERNAME 属性中的 username 关联的密码, 按 Section 15.4 所述计算消息完整性值. 如果所得值与 MESSAGE-INTEGRITY 属性的内容不匹配, 服务器必须使用错误响应拒绝该请求. 此响应必须使用错误码 401 (Unauthorized). 它必须包含 REALM 和 NONCE 属性, 并且不应该包含 USERNAME 或 MESSAGE-INTEGRITY 属性.

如果这些检查通过, 服务器继续处理请求. 服务器生成的任何响应 (上述情况除外) 必须包含 MESSAGE-INTEGRITY 属性, 该属性使用用于认证请求的 username 和 password 计算. REALM, NONCE 和 USERNAME 属性不应该被包含.

10.2.3. 接收响应 (Receiving a Response)

如果响应是错误码为 401 (Unauthorized) 的错误响应, 客户端应该使用新的事务重试该请求. 此请求必须包含 USERNAME, 其值由客户端根据错误响应中的 REALM 确定为适当的 username. 请求必须包含从错误响应复制的 REALM. 请求必须包含从错误响应复制的 NONCE. 请求必须包含 MESSAGE-INTEGRITY 属性, 该属性使用与 USERNAME 属性中的 username 关联的密码计算. 如果客户端没有从上一次尝试更改 USERNAME 或 REALM 或其关联密码, 则客户端不得执行此次重试.

如果响应是错误码为 438 (Stale Nonce) 的错误响应, 客户端必须使用 438 (Stale Nonce) 响应中提供的新 NONCE 重试该请求. 此重试也必须包含 USERNAME, REALM 和 MESSAGE-INTEGRITY.

客户端在响应 (无论成功或失败) 中查找 MESSAGE-INTEGRITY 属性. 如果存在, 客户端使用请求所用的同一密码, 按 Section 15.4 中定义的方式计算该响应的消息完整性. 如果所得值与 MESSAGE-INTEGRITY 属性的内容匹配, 则认为响应已通过认证. 如果值不匹配, 或者 MESSAGE-INTEGRITY 不存在, 响应必须被丢弃, 就好像从未收到过一样. 这意味着在适用时, 重传会继续进行.