摘要

  • RFC9470 处理访问令牌所关联认证事件的强度和新近程度,不是仅看令牌何时签发。同一授权响应衍生的令牌续发保留原有认证信息,不能把续发本身当成新的用户认证事件。
  • 资源端需要通过所选验证方法取得并评估实际认证证据。扩展建议满足所请求的认证上下文,或明确返回失败,而不是不断交付仍然不符合要求的令牌。
  • 令牌有效性、认证时间与上下文、授权范围和操作结果是不同判断。共同的请求与证据契约不把 OAuth 变成认证协议,也不要求所有操作都向一个中央机构重新申请许可。

仪表盘上的新令牌,未必是资源端需要的新证据

设想一个运行面板:访问令牌持续签发,更新成功率看起来很好,服务也保持可用。与此同时,受保护资源要求用户最近主动完成过认证。客户端获得的令牌来自较早的同一授权响应,期间没有新的用户认证事件。面板并不一定说错了什么,它确实记录了新的签发;但它没有回答资源端关心的那件事。

这是假设性的设计场景,不是本篇在某个产品中发现的故障。它的作用,是先把两只时钟分开,再讨论所谓“新”。令牌作为凭据可以很新,所关联的认证事件却可以更早。反过来,如果实际认证事件已经满足资源策略,也不必推导出用户每执行一次操作就必须重新交互。判断依据是具体条件与真实证据,而不是一条普遍要求不断弹出认证页面的规则。

2023 年 9 月发布的 RFC9470 定义了 OAuth 2.0 增强认证挑战协议。资源端可以借它说明,令牌所关联认证事件的强度或新近程度不足。协议本身不定义认证用户的具体机制。它依赖单独的认证层,并明确禁止把本文件用于将 OAuth 定位成认证协议。增强认证信息可以参与授权判断,不等于 OAuth 接管了认证本身。

这一边界首先限制了语言上的跳跃。新的授权请求不自动意味着用户刚重新登录;拿到新的令牌不自动意味着请求的认证等级已达到;认证条件通过也不自动意味着权限范围足够,或操作已经执行成功。把这些事实都写成“刷新完成”,看似简洁,却会抹掉不同参与者各自需要证明的内容。

JWT 的 iat 字段体现了其中一只时钟。RFC7519 把它定义为 JWT 签发的时间,可以用来判断 JWT 的年龄,并不是用户上一次主动认证的时间。一般规范中该字段可选,具体令牌配置可以有自己的要求,不能用一般可选性覆盖特定配置。更重要的是,即便签发时间已被正确验证,也不能拿它补出一条缺失的用户认证时间证据。

RFC9068 允许在相关授权中携带 auth_time、acr、amr 等认证信息。对由同一授权响应衍生的访问令牌,这些值保持固定,包括通过刷新或令牌交换取得的后续令牌。RFC9470 对 auth_time 和 acr 再次说明了认证事件与令牌续发的区别。这里必须保留“同一响应衍生”的限定:如果用户确实完成了新的认证,那是新的证据;不能声称任何可能的续发流程都绝不会涉及认证。

所以,问题不是反对自动更新凭据。更新可以维护服务连续性,也可以配合其他安全控制。问题在于,签发过程的成功没有权力把一个未重演的认证事件改成刚发生。资源端如果要求事件足够新,就需要知道该事件何时发生,而不是只知道凭据何时再次生产。

资源端请求的是认证条件,不是一个漂亮的新时间戳

insufficient_user_authentication 表示资源端的认证要求没有得到满足,并不自动等同于令牌过期,也不等同于所有权限范围都不足。挑战可以包含 acr_values,用按偏好排列的上下文类别说明接受哪些认证条件;也可以包含 max_age,说明允许距主动认证事件经过多少秒。两项可以同时出现;如果 scope 也不足,可以按引用的 Bearer 规则一并说明。

上下文类别名称并不亲自完成认证。OpenID Connect Core 要求参与者约定这些值的含义,而含义可能与具体场景有关。一个字符串放在标准字段里,不会因此自动证明某一种认证技术或一个全球通用的保证等级。资源端需要知道自己接受什么,授权服务器也需要知道什么事件能够满足那种含义。

max_age 则是非负整数表示的事件时间限制,不是访问令牌最大签发年龄。只检查最新凭据的时间戳,不能证明距离用户主动认证经过了多久。这不是本篇对真实部署的漏洞判定,而是对证据要求的限定:在宣称认证足够新之前,系统要能够回答正确的时间问题。

客户端应解析挑战中实际出现的参数,并用于构造授权请求。把条件准确送达是有用的协调,但仍不是条件已实现的证据。请求被转发、浏览器完成跳转、令牌被返回,分别只能说明各自阶段的事情;资源端还需要检查返回的认证信息,而不能用这一串流程的顺利运行代替最终判断。

满足条件,或者把没有满足说清楚

OpenID Connect Core 对一般 acr_values 请求的处理,涉及一个自愿提供的属性。不能从 ID Token 中的上下文处理规则推导出任何等级都会被无条件实现。它的 max_age 规则还要求,在超过允许时长后尝试让用户主动重新认证,并在返回的身份令牌中包含 auth_time。但身份令牌的要求,也不能直接证明任意访问令牌含有什么内容。

RFC9470 针对符合其扩展的授权服务器说明访问令牌行为,包括响应相关参数时携带 acr 和 auth_time。更关键的是,它建议将请求的 acr 值视为成功履行请求的必要条件:认证达到要求则返回相应值,否则以 unmet_authentication_requirements 明确失败,而不是再次交付一个资源端仍然认为不足的令牌。

两边都不能夸大。把扩展说成只有一种永远可以忽略的偏好,会弱化它对访问令牌的建议;把任何挑战说成保证一定能完成更强认证,则会制造规范没有给出的承诺。当条件无法实现,明确失败可能就是适当结果。OpenID 的未满足认证要求扩展提供了这种错误信息,但错误名称不增加授权范围,也不证明保护操作已经发生。

在假设场景中,循环挑战可能来自无法达到的上下文、不能证明足够新的事件,或两端无法兼容的政策。本篇没有在现实供应商中观察到这些情形。它们说明,单看新令牌的签发时间并不能定位分歧。相关服务应解释可达到的条件和终止结果,而不是把每一次新的凭据返回都记作走向操作成功的进展。

明确失败也改变了责任展示方式。对授权服务器而言,返回令牌可以维持一次事务成功的表象;对资源而言,返回的东西可能还是不可用。RFC9470 的建议让“条件没有达到”保留为可见状态。服务体验可以优化,不能靠不断展示局部成功把失败条件从记录里消失掉。

两条证据路径,不意味着一种普遍架构

RFC9470 结合两种常见访问令牌验证方法说明认证信息:一种是按适用配置验证的 JWT 访问令牌,另一种是 OAuth 令牌状态查询,即内省。其他编码与验证方法也可以选用,只是超出该文件范围。资源端需要取得有关事件的证据,不等于所有采用者必须运行一模一样的在线系统。

对 JWT,读取 auth_time、acr 等字段并不能代替验证令牌。适用配置中的签发者、受众以及其他检查仍然重要,随后才是认证信息的含义和策略判断。一个未经信任的输入带有熟悉字段名称,也不会自动成为证据。这是概念上的责任边界,不是对特定实现开展的安全审计。

对状态查询,active:true 也不是“所有访问政策已通过”的缩写。令牌可以处于活跃状态,所关联认证事件却比资源允许的更早,或属于资源不接受的上下文。RFC7662 提供状态和元数据查询,RFC9470 加入有关认证事件的响应成员。事件信息需要独立评估,不能由一个活跃标志全部包办。

因此,内省的存在并不要求每一次操作都向在线权威机构查询;JWT 的存在也不证明离线检查在所有场景都足够。部署需要依据责任及其他要求选择适当的证据路径。共同契约可以描述传递什么,而不必替所有资源规定唯一的运行模式。把技术选项提升成普遍中央许可制度,是另一项没有从这里得到依据的决定。

授权服务器元数据提供的也是有限信号。依 RFC9470,acr_values_supported 表明它理解并遵循相关请求参数。这是能力声明,不是某个用户事件已成功的记录,不是实际认证年龄,也不是资源操作完成的证明。能力目录、认证证据与操作结果,即使都由同一家服务提供,也仍是不同对象。

认证条件通过,也不会凭空扩大权限

OAuth 的刷新规则禁止请求超出原先授予范围的 scope;省略该项时保留原范围。令牌端点对客户端的认证,也不等于最终用户最近主动完成过认证。一次自动事务既不能因此证明用户新近出现,也不能因此增加用户原先没有的操作权限。

资源可以把认证质量作为访问条件,但它不是完整决定。有效性、受众、范围、上下文和新近程度,可能分别需要满足。某一个条件通过不会创造其他条件;所有必要条件都通过,也仍不证明实际业务操作已经执行成功。报告“成功”之前,要先说清楚到底是哪件事情成功了。

消息表达得清楚,不等于政策一定能兼容

RFC9470 不对资源端与授权服务器组成的政策对施加具体限制。某个部署完全可能提出用户无法达到的要求,或产生不理想的使用体验。怎样完成某项认证条件,例如需要什么设备,也并非仅由类别名称决定。共同语法解决了条件如何传递,不会把所有条件变成每个人都能实现的事情。

挑战甚至不证明收到的令牌已经被验证。规范允许把挑战判断安排在一般验证之前或之后,也允许在没有先验证有效令牌时返回挑战,并指出这可能向尚未证明能取得相应凭据的主体暴露要求。处理顺序是带有后果的部署选择,不能由本篇自行改写成一条所有系统都必须采用的顺序。

认证上下文值也可能暴露其他信息。例如,不同用户被要求达到不同条件,可能泄露高权限身份的线索。资源能够触发用户交互,也意味着恶意资源可能滥用这种功能。本篇没有观察到真实攻击或受害者。标准中的风险说明支持谨慎处理这一机制,不支持声称已经知道现有服务中发生了多少次。

RFC9700 提供更新后的 OAuth 安全背景,却不是另一只认证时钟。刷新令牌轮换、加强凭据保护等控制各有针对的问题,不会自动证明用户刚进行了认证。这并不意味着这些控制无用,而是不同控制可以互补,却不能任意成为彼此的证据。安全措施的数量不能替代事件之间的区别。

卢恒提出的最小初始规格、本地化未来决策和自愿采用,为这种分工提供了编辑参照。共同层可以让请求条件与认证证据可理解,相关资源与服务对负责说明自己的操作政策和可实现条件,采用者再据此选择。没有必要新设一个机构逐次批准所有操作;也不能用本地责任为借口,把条件及其不可实现性藏起来。

一枚新令牌可以参与可靠决定,但它本身不是新认证事件、条件已满足和操作已完成的替代品。把这些事实保持可区分,共同协议才真正是在降低协调成本,而不是让签发时钟获得本来不属于它的判断权。

来源