这是一份对 RFC 9767 的中文翻译。请注意,这是一个技术性很强的文档,翻译力求准确传达技术含义,但可能不完全符合文学性的中文表达习惯。关键术语和协议字段名保留了英文原文以便对照。
[文件名称]: rfc9767.txt
[文件内容开始]
Internet Engineering Task Force (IETF) J. Richer, Ed.
Request for Comments: 9767 Bespoke Engineering
Category: Standards Track F. Imbault
ISSN: 2070-1721 acert.io
April 2025
授权协商与授权协议(GNAP)资源服务器连接
摘要
授权协商与授权协议(GNAP)定义了一种机制,用于将授权委托给一个软件(客户端),并将该委托的结果和凭证传递给该软件。本扩展定义了资源服务器(RS)以可互操作的方式与授权服务器(AS)连接的方法。
关于本文档的状态
这是一个互联网标准轨迹文档。
本文档是互联网工程任务组(IETF)的产品。它代表了IETF社区的共识。它已经接受了公众审查,并已被互联网工程指导小组(IESG)批准发布。关于互联网标准的更多信息可在 RFC 7841 的第 2 节中找到。
关于本文档的当前状态、任何勘误以及如何提供反馈的信息,可以在 https://www.rfc-editor.org/info/rfc9767 获得。
版权声明
版权所有 (c) 2025 IETF 信托基金和被标识为文档作者的个人。保留所有权利。
本文档受 BCP 78 和 IETF 信托基金关于 IETF 文档的法律条款(https://trustee.ietf.org/license-info)的约束,这些条款在本文档发布之日有效。请仔细阅读这些文档,因为它们描述了您对本文档的权利和限制。从本文档中提取的代码组件必须包含信托法律条款第 4.e 节中描述的修订版 BSD 许可证文本,并且不提供修订版 BSD 许可证中描述的担保。
目录
1. 引言
1.1. 术语
2. 访问令牌
2.1. 通用访问令牌模型
2.1.1. 值
2.1.2. 签发者
2.1.3. 受众
2.1.4. 密钥绑定
2.1.5. 标志
2.1.6. 访问权限
2.1.7. 时间有效性窗口
2.1.8. 令牌标识符
2.1.9. 授权资源所有者
2.1.10. 最终用户
2.1.11. 客户端实例
2.1.12. 标签
2.1.13. 父授权请求
2.1.14. AS 特定的访问令牌
2.2. 访问令牌格式
3. 面向资源服务器的 API
3.1. RS 面对的 AS 发现
3.2. 保护 RS 向 AS 发出的请求
3.3. 令牌内省
3.4. 注册资源集
3.5. 错误响应
4. 派生下游令牌
5. IANA 考虑事项
5.1. 知名 URI
5.2. GNAP 授权请求参数
5.3. GNAP 令牌格式
5.3.1. 注册表模板
5.3.2. 初始注册表内容
5.4. GNAP 令牌内省请求
5.4.1. 注册表模板
5.4.2. 初始注册表内容
5.5. GNAP 令牌内省响应
5.5.1. 注册表模板
5.5.2. 初始注册表内容
5.6. GNAP 资源集注册请求参数
5.6.1. 注册表模板
5.6.2. 初始注册表内容
5.7. GNAP 资源集注册响应参数
5.7.1. 注册表模板
5.7.2. 初始注册表内容
5.8. GNAP RS 面对的发现文档字段
5.8.1. 注册表模板
5.8.2. 初始注册表内容
5.9. GNAP RS 面对的错误代码
5.9.1. 注册模板
5.9.2. 初始内容
6. 安全考虑事项
6.1. 传输中的 TLS 保护
6.2. 令牌验证
6.3. 缓存令牌验证结果
6.4. 密钥证明验证
6.5. 令牌外泄
6.6. RS 对令牌的重复使用
6.7. 令牌格式考虑事项
6.8. 令牌内容过度共享
6.9. 资源引用
6.10. 来自不受信任 AS 的令牌重新签发
6.11. 令牌密钥的内省
6.12. RS 注册和管理
7. 隐私考虑事项
7.1. 令牌内容
7.2. 通过内省披露令牌使用情况
7.3. 将用户映射到 AS
8. 参考文献
8.1. 规范性参考文献
8.2. 参考性文献
致谢
作者地址
1. 引言
核心 GNAP 规范 [GNAP] 为授权服务器(AS)和资源服务器(RS)定义了不同的角色。然而,核心规范并未定义 RS 如何获取重要问题的答案,例如某个访问令牌是否仍然有效,或者该访问令牌被批准了哪些访问权限集合。
虽然 AS 和 RS 可能紧密耦合(例如,共享同一服务器和存储),但 GNAP 并不假定或要求这种紧密耦合。AS 和 RS 分开运行和管理的情况越来越普遍,特别是在单个 AS 同时保护多个 RS 的情况下。
本规范定义了一组面向 RS 的 API,AS 可以为高级的松散耦合部署提供这些 API。此外,本文档定义了一个通用的访问令牌模型,该模型可用于结构化的、格式化的访问令牌或令牌内省响应中。本规范还定义了一种方法,供 RS 派生一个下游令牌以调用另一个链式 RS。
授权服务器向客户端实例发放访问令牌的方式,以及客户端实例向资源服务器出示访问令牌的方式,是核心 GNAP 规范 [GNAP] 的主题。
1.1. 术语
本文档中使用的关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY" 和 "OPTIONAL" 应按照 BCP 14 [RFC2119] [RFC8174] 中的描述进行解释,当且仅当它们以全大写字母出现时,如本文所示(在本翻译中以 黑体 形式表明)。
本文档包含部分和完整 HTTP 消息、JSON 结构、URL、查询组件、密钥和其他元素的无规范性示例。一些示例使用单个尾随反斜杠 \ 表示长值的换行,遵循 [RFC8792]。\ 字符和换行行首的空格不是值的一部分。
特定于 GNAP 的术语在核心规范的术语部分定义;参见 [GNAP] 的第 1.1 节。定义了以下协议角色:授权服务器、客户端、最终用户、资源所有者和资源服务器。定义了以下协议元素:访问令牌、属性、授权、权限、受保护资源、权利、主体和主体信息。本文档使用相同的定义。
2. 访问令牌
访问令牌用作 AS 向客户端实例提供对 RS 有限访问的一种机制。这些访问令牌是代表客户端实例被授予的、代表 RO 行事的一组特定访问权限的凭证。虽然访问令牌的格式在不同系统中各不相同(参见第 2.2 节的讨论),但访问令牌的概念在所有 GNAP 系统中是一致的。
2.1. 通用访问令牌模型
核心 GNAP 规范 [GNAP] 侧重于客户端和 AS 之间的关系。由于访问令牌对客户端是不透明的,核心规范没有定义令牌模型。然而,AS 需要创建令牌,RS 需要理解令牌。为了促进一定程度的互操作性,这里提出了一个通用的访问令牌模型。访问令牌代表了不同 GNAP 部署中一组通用的方面。这个列表并非旨在通用或全面,而是作为指导实施者在 GNAP 部署中开发数据结构和相关系统的指南。这些数据结构通过使用结构化令牌或类似 API 的机制(如令牌内省,参见第 3.3 节)在 AS 和 RS 之间传递。
这个通用数据模型不假定任何一种方法;事实上,两种方法可以一起使用来传递不同的信息片段。在可能的情况下,为模型中的每个项目提供了到 JSON Web Token (JWT) [JWT] 标准格式的映射。
2.1.1. 值
所有访问令牌都有一个 值,这是在各方之间在线路上传递的字符串。为了在运行时区分不同的访问令牌,令牌的值需要在安全域(例如由 AS 控制的所有系统)内是唯一的。否则,两个独立的令牌会被混淆,这将导致安全问题。AS 选择该值,该值可以是结构化的(参见第 2.2 节)或非结构化的。当令牌是结构化时,令牌值也具有 AS 和 RS 已知的 格式,并且此令牌模型中的其他项目以某种方式包含在令牌的值中。当令牌是非结构化时,这些值通常由 RS 通过诸如第 3.3 节描述的令牌内省等服务来检索。
访问令牌值在 access_token 响应的 value 字段中传递;参见 [GNAP] 的第 3.2 节。
访问令牌值的格式和内容对客户端软件是不透明的。虽然客户端软件需要能够携带和出示访问令牌值,但客户端软件本身从不期望也不打算能够理解令牌值本身。
如果使用像 [JWT] 那样的结构化令牌,令牌的值可能不会被 AS 存储。相反,可以使用令牌标识符并辅以 AS 生成的签名来验证和识别单个令牌。
2.1.2. 签发者
访问令牌由 [GNAP] 中定义的 AS 签发。AS 需要标识自己,以便让 RS 识别 AS 已签发的令牌,特别是在可能向同一个 RS 出示来自多个不同 AS 的令牌的情况下。
这些信息通常不直接传递给客户端实例,因为客户端实例应该根据它从哪里收到令牌来知道这些信息。
在 JSON Web Token [JWT] 的有效载荷或令牌内省响应中,这对应于 iss 声明。
2.1.3. 受众
访问令牌旨在供一个或多个 RS 使用。AS 可以列出令牌的目标 RS,以允许每个 RS 确保它没有收到打算给其他人的令牌。AS 和 RS 必须就令牌所代表的任何受众标识符的性质达成一致,但 RS 的 URI 是一种常见模式。
在 JSON Web Token [JWT] 的有效载荷或令牌内省响应中,这对应于 aud 声明。
在需要更复杂访问的情况下,access 数组中对象的 location 字段也可以传递受众信息。在这种情况下,客户端实例可能需要知道受众信息,以便区分可能出示令牌的 RS。
2.1.4. 密钥绑定
GNAP 中的访问令牌绑定到客户端实例注册或出示的密钥,除非访问令牌是持有者令牌。对于所有绑定到密钥的令牌,AS 和 RS 需要能够识别令牌绑定到哪个密钥;否则,攻击者可以在出示令牌时替换自己的密钥。在非对称算法的情况下,AS 和 RS 只需要知道公钥,而客户端实例还需要知道私钥才能出示令牌。在对称算法的情况下,所有方都需要知道或能够派生共享密钥。
此密钥信息的来源可能因部署决策而异。例如,AS 可以决定颁发给客户端实例的所有令牌始终绑定到该客户端实例的当前密钥。当需要解引用密钥时,AS 查找令牌颁发给的客户端实例,并在那里找到密钥信息。或者,AS 可以将每个令牌绑定到一个独立于客户端实例信息管理的特定密钥。在这种情况下,AS 直接确定密钥信息。这种方法允许客户端实例对每个请求使用不同的密钥,或者允许 AS 为客户端实例颁发一个用于特定令牌的密钥。
在所有情况下,密钥绑定还包括一个证明机制,以及该机制所需的任何参数,例如签名或摘要算法。如果此类信息未包含在证明密钥中,攻击者可能使用看似有效但使用了不安全和不正确证明机制的密钥来出示令牌。
该值在 [GNAP] 第 3.2 节的 access_token 响应的 key 字段中传递给客户端实例。由于常见情况是令牌绑定到客户端实例的注册密钥,因此在这种情况下可以省略此字段,因为客户端将知道自己的密钥。
在 JSON Web Token [JWT] 的有效载荷中,这对应于 cnf(确认)声明。在令牌内省响应中,这对应于 key 声明。
在持有者令牌的情况下,所有方都需要知道令牌没有绑定任何密钥,因此将拒绝任何以未定义方式使用持有者令牌与密钥的尝试。
2.1.5. 标志
GNAP 访问令牌可以有多个相关的数据标志,这些标志指示令牌的特殊处理或注意事项。例如,数据标志可以指示令牌是持有者令牌,还是应在授权更新时持久保存。
客户端可以使用 [GNAP] 第 2.1.1 节中 access_token 授权请求参数的 flags 字段请求一组标志。
这些标志在 [GNAP] 第 3.2 节授权响应的 access_token 部分的 flags 字段中从 AS 传递给客户端。
对于令牌内省,标志在响应的 flags 字段中返回。
2.1.6. 访问权限
访问令牌与一组有限的访问权限相关联。这些权限详细说明了令牌可以用于什么、如何使用以及在哪里使用。访问权限的内部结构在 [GNAP] 的第 8 节中有详细说明。
与访问令牌关联的访问权限是根据发出请求的客户端实例可用的权限、RO 可批准授予的权限、RO 实际批准的权限以及对应 RS 的权限计算得出的。特定访问令牌的权限是授权请求中整体权限的一个子集。
这些权限由客户端实例在 access_token 请求的 access 字段中请求;参见 [GNAP] 的第 2.1 节。
与已颁发的访问令牌关联的权限在 [GNAP] 第 3.2 节的 access_token 响应的 access 字段中传递给客户端实例。
在令牌内省响应中,访问权限对应于 access 声明。
2.1.7. 时间有效性窗口
访问令牌可以限制在某个时间窗口内,在此窗口之外,它在 RS 处不再有效使用。此窗口可以由到期时间和不早于时间显式界定,或者可以根据令牌的颁发时间计算。例如,RS 可以决定对于大多数调用,它接受令牌颁发后一小时内的令牌,但对于某些高价值调用,只接受令牌颁发后五分钟内的令牌。
由于访问令牌可能因客户端实例控制之外的任何原因随时被撤销,客户端实例通常不知道或不关心访问令牌的有效时间窗口。但是,可以通过使用访问令牌响应的 expires_in 字段使其可用;参见 [GNAP] 的第 3.2 节。
令牌的颁发时间在 JSON Web Token [JWT] 的有效载荷或令牌内省响应的 iat 声明中传递。
令牌的到期时间,在此之后应被拒绝,在 JSON Web Token [JWT] 的有效载荷或令牌内省响应的 exp 声明中传递。
令牌有效性窗口的开始时间,在此之前应被拒绝,在 JSON Web Token [JWT] 的有效载荷或令牌内省响应的 nbf 声明中传递。
2.1.8. 令牌标识符
单个访问令牌通常需要一个唯一的内部标识符,以便 AS 区分多个独立的令牌。令牌的值通常可以用作标识符,但在某些情况下,会使用单独的标识符。
这个单独的标识符可以在 JSON Web Token [JWT] 的有效载荷或令牌内省响应的 jti 声明中传递。
这个标识符通常不会暴露给使用令牌的客户端实例,因为客户端实例只需要按值使用令牌。
2.1.9. 授权资源所有者
访问令牌是代表资源所有者(RO)批准的。该 RO 的身份可供 RS 用于确定要访问的确切资源或允许的访问类型。例如,用于访问身份信息的访问令牌可以包含用户标识符,以允许 RS 确定返回哪个配置文件信息。此信息的性质需经 AS 和 RS 同意。
这对应于 JSON Web Token [JWT] 的有效载荷或令牌内省响应中的 sub 声明。
当单独请求访问令牌时,详细的 RO 信息不会返回给客户端实例,并且在许多情况下,将这些信息返回给客户端实例将是 AS 的隐私侵犯。由于访问令牌代表特定的委托访问,客户端实例只需要在其目标 RS 处使用该令牌。以前面的配置文件为例,客户端实例不需要知道帐户标识符来获取令牌所代表的帐户的特定属性。
GNAP 确实允许单独于访问令牌返回主体信息,以标识符和断言的形式。这些值直接返回给客户端,与任何请求的访问令牌分开,尽管它们通常代表同一方。
2.1.10. 最终用户
最终用户是操作客户端软件的一方。客户端实例可以促进最终用户与 AS 交互,以确定最终用户的身份、收集授权,并将该信息的结果提供回客户端实例。
在许多情况下,最终用户与资源所有者是同一方。然而,在某些情况下,这两个角色可以由不同的人履行,其中 RO 是异步咨询的。令牌模型应该能够通过分别表示最终用户和 RO 来反映这类情况。例如,最终用户可以请求财务支付,但 RO 是支付将从中提取的帐户的持有者。AS 将在 GNAP 请求流程之外咨询 RO 以获得批准。在这种情况下,令牌需要将 RO 和最终用户显示为独立的实体。
2.1.11. 客户端实例
访问令牌由 AS 颁发给特定的客户端实例。该实例的身份可供 RS 用于允许特定类型的访问或访问令牌的其他属性。例如,一个 AS 将其颁发给特定客户端实例的所有访问令牌绑定到该客户端实例最近的密钥轮换,它将需要能够查找客户端实例以找到密钥绑定细节。
这对应于 JSON Web Token [JWT] 有效载荷中的 client_id 声明,或令牌内省响应中的 instance_id 字段。
客户端通常不会单独被告知此信息,因为客户端实例通常可以正确假设它是收到令牌的客户端实例。
2.1.12. 标签
当请求多个访问令牌或客户端实例使用令牌标签时,各方将需要跟踪哪些标签应用于每个单独的令牌。由于标签可以在不同的授权请求中重复使用,仅凭令牌标签不足以唯一标识系统中的给定访问令牌。但是,在授权请求的上下文中,这些标签必须是唯一的。
客户端实例可以使用 access_token 请求的 label 字段请求特定标签;参见 [GNAP] 的第 2.1 节。
AS 可以使用 access_token 响应的 label 字段通知客户端实例令牌的标签;参见 [GNAP] 的第 3.2 节。
这对应于令牌内省响应的 label 字段。
2.1.13. 父授权请求
所有访问令牌都是在客户端实例的特定授权请求的上下文中颁发的。授权请求本身代表一个唯一的元组:
- 处理授权请求的 AS
- 提出授权请求的客户端实例
- 批准(或需要批准)授权请求的 RO(或 RO 集合)
- RO 授予的访问权限
- 授权请求的当前状态,如 [GNAP] 第 1.5 节所定义
AS 可以使用此信息将公共信息与特定令牌关联起来。例如,AS 可以将客户端信息存储在授权本身中,并通过访问令牌的引用进行查找,而不是为授权中的每个颁发的访问令牌指定客户端实例。
AS 也可以在授权请求更新时使用此信息。例如,如果客户端实例从现有授权请求新的访问令牌,AS 可以使用此链接撤销先前在该授权下颁发的非持久性访问令牌。
客户端实例将拥有其正在进行的授权请求的自己的模型,特别是如果该授权请求可以使用 [GNAP] 第 5 节定义的 API 继续,其中需要保持一些状态性。客户端实例可能需要与颁发令牌的授权请求保持关联,以防访问令牌过期或没有足够的访问权限,这样客户端实例就可以获得新的访问令牌,而无需从头重新启动授权请求过程。
由于授权本身不需要在协议消息中的任何地方被标识,GNAP 没有定义特定的授权标识符在协议的任何方之间传递。只有 AS 需要明确保持已颁发的访问令牌与其父授权之间的连接。
2.1.14. AS 特定的访问令牌
当访问令牌用于 [GNAP] 第 5 节定义的授权继续 API(继续访问令牌)、[GNAP] 第 6 节定义的令牌管理 API(令牌管理访问令牌)或第 3 节定义的面向 RS 的 API(资源服务器管理访问令牌)时,AS 必须 将这些访问令牌与其他在一个或多个 RS 处使用的访问令牌分开。AS 可以通过在访问令牌数据结构上使用标志、使用特殊的内部访问权限或任何其他可用的方式来实现这一点。与 GNAP 中的其他访问令牌一样,出示令牌的软件对这些 AS 特定访问令牌的内容是不透明的。与其他访问令牌不同,这些 AS 特定访问令牌的内容对 RS 也是不透明的。
客户端实例仅在 [GNAP] 第 3.1 节授权响应的 continue 字段中获取继续访问令牌。客户端实例仅在 [GNAP] 第 3.2.1 节授权响应的 manage 字段中获取令牌管理访问令牌。RS 获取资源服务器管理访问令牌的方式超出了本规范的范围,但方法可能包括在 RS 软件中预先配置令牌值或通过标准的 GNAP 流程授予访问令牌。
对于继续访问令牌和令牌管理访问令牌,客户端实例 必须 采取措施将这些特殊用途的访问令牌与在一个或多个 RS 处使用的访问令牌区分开来。为此,客户端实例可以将 AS 特定的访问令牌与其他访问令牌分开存储,以防止它们相互混淆并在错误的端点使用。
RS 永远不应该看到出示的 AS 特定访问令牌,因此任何处理它的尝试 必须 失败。当使用内省时,AS 不得 向 RS 返回 AS 特定访问令牌的 active 值为 true。如果 AS 以内部使用令牌内省的方式实现其受保护的端点,AS 必须 将这些 AS 特定的访问令牌与为外部 RS 使用而颁发的访问令牌区分开。
2.2. 访问令牌格式
当 AS 颁发访问令牌供 RS 使用时,RS 需要某种方式来理解访问令牌的用途,以便确定如何响应请求。核心 GNAP 协议对访问令牌的格式或内容既不假设也不要求,事实上,令牌格式和内容对客户端实例是不透明的。然而,此类令牌格式可以是 AS 和 RS 之间协议的主题。
自包含的结构化令牌格式允许在 AS 和 RS 之间传递信息,而无需 RS 在运行时调用 AS,如第 3.3 节所述。结构化令牌也可以与内省结合使用,允许令牌本身携带一类信息,而内省响应携带另一类信息。
一些令牌格式,例如 Macaroons [MACAROON] 和 Biscuits [BISCUIT],允许 RS 派生子令牌,而无需调用 AS,如第 4 节所述。
支持的令牌格式可以在运行时在 AS 和 RS 之间的几个地方动态通信:
- AS 可以在 RS 面对的发现(第 3.1 节)中声明其支持的令牌格式。
- RS 可以要求使用特定的令牌格式来访问已注册的资源集(第 3.4 节)。
- AS 可以在内省响应(第 3.3 节)中返回令牌的格式。
在所有明确列出令牌格式的地方,它 必须 是第 5.3 节 "GNAP 令牌格式" 注册表中的注册值之一。
3. 面向资源服务器的 API
为了促进与 RS 的运行时和动态连接,AS 可以提供一个面向 RS 的 API,由以下一个或多个可选部分组成:
- 发现
- 内省
- 令牌链式传递
- 资源引用注册
3.1. RS 面对的 AS 发现
提供 RS 面向服务的 GNAP AS 可以在一个知名发现文档上发布其功能,该文档位于与授权请求端点 URL 具有相同模式和权限的 URL,路径为 /.well-known/gnap-as-rs
。
发现响应是一个 JSON 文档 [RFC8259],由单个 JSON 对象组成,包含以下字段:
grant_request_endpoint
(字符串): AS 的授权请求端点的位置,由 [GNAP] 的第 9 节定义。此 URL 必须 是客户端实例在支持 GNAP 请求时使用的相同 URL。RS 可以使用此 URL 来派生下游访问令牌(如果 AS 支持)。位置 必须 是一个 URL [RFC3986],其方案组件 必须 是 https,包含主机组件,以及(可选地)端口、路径和查询组件,没有片段组件。必需。参见第 4 节。introspection_endpoint
(字符串): 提供内省的端点的 URL。位置 必须 是一个 URL [RFC3986],其方案组件 必须 是 https,包含主机组件,以及(可选地)端口、路径和查询组件,没有片段组件。如果 AS 支持内省,则 必需。缺少值表示 AS 不支持内省。参见第 3.3 节。token_formats_supported
(字符串数组): 此 AS 支持的令牌格式列表。此列表中的值 必须 在第 5.3 节的 "GNAP 令牌格式" 注册表中注册。可选。resource_registration_endpoint
(字符串): 提供资源注册的端点的 URL。位置 必须 是一个 URL [RFC3986],其方案组件 必须 是 https,包含主机组件,以及(可选地)端口、路径和查询组件,没有片段组件。如果 AS 支持动态资源注册,则 必需。缺少值表示 AS 不支持此功能。参见第 3.4 节。key_proofs_supported
(字符串数组): AS 支持的密钥证明机制列表。此列表的值对应于请求的 key 部分的 proof 字段的可能值。值 必须 在 [GNAP] 建立的 "GNAP 密钥证明方法" 注册表中注册。可选。
其他字段在 "GNAP RS 面对的发现文档字段" 注册表中定义;参见第 5.8 节。
3.2. 保护 RS 向 AS 发出的请求
除非另有说明,RS 必须 使用 [GNAP] 第 7 节定义的任何签名方法来保护其对 AS 的调用。
RS 可以 通过引用或值来出示其密钥,类似于客户端实例在 GNAP 核心协议中调用 AS 的方式,如 [GNAP] 第 7.1 节所述。在此处定义的协议中,这采用资源服务器使用 key 字段或直接传递实例标识符来标识自己的形式。
POST /continue HTTP/1.1
Host: server.example.com
Authorization: GNAP 80UPRY5NM33OMUKMKSKU
Signature-Input: sig1=...
Signature: sig1=...
Content-Type: application/json
"resource_server": {
"key": {
"proof": "httpsig",
"jwk": {
"kty": "EC",
"crv": "secp256k1",
"kid": "2021-07-06T20:22:03Z",
"x": "-J9OJIZj4nmopZbQN7T8xv3sbeS5-f_vBNSy_EHnBZc",
"y": "sjrS51pLtu3P4LUTVvyAIxRfDV_be2RYpI5_f-Yjivw"
}
}
}
或通过引用:
POST /continue HTTP/1.1
Host: server.example.com
Signature-Input: sig1=...
Signature: sig1=...
Content-Type: application/json
{
"resource_server": "7C7C4AZ9KHRS6X63AJAO"
}
RS 的密钥如何被 AS 知晓的方式超出了本规范的范围。AS 可以 要求 RS 预先注册其密钥,或者它可以允许来自任意密钥的调用,采用首次使用信任模型。
AS 可以 向 RS 颁发访问令牌,称为 "资源服务器管理访问令牌",以保护面向 RS 的 API 端点。如果颁发了此类令牌,RS 必须 在向面向 RS 的 API 端点发出请求时,连同 RS 身份验证一起出示它们。
POST /continue HTTP/1.1
Host: server.example.com
Authorization: GNAP 80UPRY5NM33OMUKMKSKU
Signature-Input: sig1=...
Signature: sig1=...
Content-Type: application/json
{
"resource_server": "7C7C4AZ9KHRS6X63AJAO"
}
3.3. 令牌内省
AS 颁发访问令牌,代表一组要在
一个或多个 RS 处使用的委托访问权限。AS 可以提供内省服务,以允许 RS 验证给定的访问令牌:
- 已由 AS 签发
- 在当前时间有效
- 未被撤销
- 适合调用中标识的 RS
当 RS 收到访问令牌时,它可以调用 AS 的内省端点以获取令牌信息。
+--------+ +------+ +------+
| Client +--(1)->| RS | | AS |
|Instance| | +--(2)->| |
| | | | | |
| | | |<-(3)--+ |
| | | | +------+
| |<-(4)--+ |
+--------+ +------+
1. 客户端实例使用其访问令牌调用 RS。
2. RS 在 AS 处内省访问令牌值。RS 使用自己的密钥(不是客户端实例的密钥或令牌的密钥)对请求进行签名。
3. AS 验证访问令牌值和 RS 的请求,并返回令牌的内省响应。
4. RS 满足客户端实例的请求。
RS 使用自己的密钥对请求进行签名,并在请求正文中以 JSON 对象的形式发送访问令牌的值,该对象包含以下成员:
access_token
(字符串): 客户端实例向 RS 出示的访问令牌值。必需。proof
(字符串): 客户端实例用于将令牌绑定到 RS 请求的证明方法。该值 必须 在 "GNAP 密钥证明方法" 注册表中注册。推荐。resource_server
(对象/字符串): 用于验证发出此调用的资源服务器的身份,按值或按引用,如第 3.2 节所述。必需。access
(字符串/对象数组): 满足请求所需的最小访问权限。这 必须 采用 [GNAP] 第 8 节描述的格式。可选。
其他字段在 "GNAP 令牌内省请求" 注册表(第 5.4 节)中定义。
POST /introspect HTTP/1.1
Host: server.example.com
Content-Type: application/json
Signature-Input: sig1=...
Signature: sig1=...
Digest: sha256=...
{
"access_token": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0",
"proof": "httpsig",
"resource_server": "7C7C4AZ9KHRS6X63AJAO"
}
AS 必须 验证访问令牌值并确定令牌是否处于活动状态。请求的参数为 AS 评估访问令牌提供了上下文,AS 必须 在评估令牌是否活动时考虑所有提供的参数。如果 AS 无法处理部分请求,例如不理解所出示的 access 字段的一部分,则 AS 不得 指示该令牌为活动状态。
活动的访问令牌定义为满足以下所有条件的令牌:
- 由正在处理的 AS 签发,
- 未被撤销,
- 未过期,
- 使用指示的证明方法绑定,
- 适合在标识的 RS 处出示,并且
- 适合所指示的访问(如果存在)。
AS 响应一个描述令牌当前状态以及 RS 验证令牌出示所需任何信息的数据结构,例如其预期的证明机制和密钥材料。
active
(布尔值): 如果为 true,则出示的访问令牌是活动的,如上所定义。如果活动令牌的任何条件不成立,或者 AS 无法做出确定(例如未找到令牌),则该值设置为 false,并省略其他字段。必需。
如果访问令牌是活动的,则包含 [GNAP] 第 3.2.1 节定义的单个访问令牌响应结构中的其他字段。特别包括以下内容:
access
(字符串/对象数组): 与此访问令牌关联的访问权限。这 必须 采用 [GNAP] 第 8 节描述的格式。此数组 可以 为所标识的 RS 的消费而进行过滤或以其他方式限制,包括为空数组,这表示该令牌没有可以披露给 RS 的显式访问权限。必需。key
(对象/字符串): 如果令牌是绑定的。绑定到访问令牌的密钥,允许 RS 验证来自客户端实例请求的签名。如果访问令牌是持有者令牌,则 不得 包含此项。必需。flags
(字符串数组): 与访问令牌关联的标志集合。可选。exp
(整数): 此令牌不再有效的时间戳。表示为自 UNIX 纪元起的整数秒数。可选。iat
(整数): 此令牌由 AS 签发的时间戳。表示为自 UNIX 纪元起的整数秒数。可选。nbf
(整数): 此令牌无效的时间戳(在此之前)。表示为自 UNIX 纪元起的整数秒数。可选。aud
(字符串或字符串数组): 此令牌可以被接受的资源服务器的标识符。可选。sub
(字符串): 授权此令牌的资源所有者的标识符。可选。iss
(字符串): 签发此令牌的 AS 的授权端点 URL。必需。instance_id
(字符串): 令牌颁发给的客户端实例的实例标识符。可选。
其他字段在 "GNAP 令牌内省响应" 注册表(第 5.5 节)中定义。
响应 可以 包含访问令牌响应中定义的任何附加字段,并且 不得 包含访问令牌值本身。
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"active": true,
"access": [
"dolphin-metadata", "some other thing"
],
"key": {
"proof": "httpsig",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"kid": "xyz-1",
"alg": "RS256",
"n": "kOB5rR4Jv0GMeL...."
}
}
}
在处理内省响应的结果时,RS 必须 确定适当的操作过程。例如,如果 RS 确定访问令牌的访问权限不足以满足令牌所附加的请求,RS 可以根据情况返回错误或公共资源。在所有情况下,响应的最终决定权在于 RS。
3.4. 注册资源集
如果 RS 需要,它可以向 AS 的资源注册端点发布一组资源(如 [GNAP] 第 8 节 "资源访问权限" 中所述),以及 RS 验证请求所需的信息。
access
(对象/字符串数组): 与请求关联的访问权限列表,格式如 [GNAP] 第 8 节("资源访问权限")所述。必需。resource_server
(对象/字符串): 用于验证发出此调用的资源服务器的身份,按值或按引用,如第 3.2 节所述。必需。token_formats_supported
(字符串数组): RS 能够处理的令牌格式列表。此数组中的值 必须 在第 5.3 节的 "GNAP 令牌格式" 注册表中注册。如果省略此字段,则令牌格式由 AS 决定。如果 AS 不支持任何请求的令牌格式,AS 必须 向 RS 返回错误。可选。token_introspection_required
(布尔值): 如果存在且设置为 true,则 RS 期望进行令牌内省请求,如第 3.3 节所述。如果不存在或设置为 false,则 RS 预计不需要对此资源集相关的令牌进行内省请求。如果 AS 不支持此 RS 的令牌内省,AS 必须 向 RS 返回错误。可选。
其他字段在 "GNAP 资源集注册请求参数" 注册表(第 5.6 节)中定义。
RS 必须 使用自己的密钥标识自己并对请求进行签名。
POST /resource HTTP/1.1
Host: server.example.com
Content-Type: application/json
Signature-Input: sig1=...
Signature: sig1=...
Digest: ...
{
"access": [
{
"actions": [
"read",
"write",
"dolphin"
],
"locations": [
"https://server.example.net/",
"https://resource.local/other"
],
"datatypes": [
"metadata",
"images"
]
},
"dolphin-metadata"
],
"resource_server": "7C7C4AZ9KHRS6X63AJAO"
}
AS 响应一个适当的引用,以表示 RS 在其请求中提出的资源列表,以及 RS 在将来请求中可能需要的任何附加信息。
resource_reference
(字符串): 表示请求中注册的资源列表的单个字符串。RS 可以 将此句柄作为 [GNAP] 第 9.1 节所述的发现响应的一部分或作为给客户端软件开发人员的文档提供给客户端实例。必需。instance_id
(字符串): RS 可以在将来调用 AS 时用来指代自身的实例标识符,代替按值发送其密钥。参见第 3.2 节。可选。introspection_endpoint
(字符串): 此 AS 的内省端点,用于允许 RS 执行令牌内省。参见第 3.3 节。可选。
其他字段在 "GNAP 资源集注册响应参数" 注册表(第 5.7 节)中定义。
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"resource_reference": "FWWIKYBQ6U56NL1"
}
如果资源先前已注册,AS 可以 返回与先前响应中相同的 resource_reference 值。
如果注册失败,AS 向 RS 返回 HTTP 状态码 400(错误请求),指示注册不成功。
然后,客户端实例可以使用 resource_reference 值作为 [GNAP] 第 8.1 节定义的字符串类型访问引用。此值 可以 与客户端实例请求的任何其他附加访问权限结合使用。
{
"access_token": {
"access": [
"FWWIKYBQ6U56NL1",
{
"type": "photo-api",
"actions": [
"read",
"write",
"dolphin"
],
"locations": [
"https://server.example.net/",
"https://resource.local/other"
],
"datatypes": [
"metadata",
"images"
]
},
"dolphin-metadata"
]
},
"client": "client-12351.bdxqf"
}
3.5. 错误响应
在来自面向 RS 的 API 出错的情况下,AS 以 HTTP 状态码 400(错误请求)响应 RS,并返回一个由单个 error 字段组成的 JSON 对象,该字段可以是对象或字符串。
当作为字符串返回时,error 值是错误代码:
{
error: "invalid_access"
}
当作为对象返回时,error 对象包含以下字段:
code
(字符串): 定义错误的单个 ASCII 错误代码。必需。description
(字符串): 面向开发者的错误的人类可读字符串描述。可选。
{
"error": {
"code": "invalid_access",
"description": "Access to 'foo' is not permitted for this RS."
}
}
本规范定义了以下错误代码值:
"invalid_request"
: 请求缺少必需参数、包含无效参数值或格式错误。"invalid_resource_server"
: 请求来自未被 AS 识别或允许的 RS,或者 RS 的签名验证失败。"invalid_access"
: RS 不允许注册或内省所请求的 "access" 值。
其他错误代码可以在 "GNAP RS 面对的错误代码" 注册表(第 5.9 节)中定义。
4. 派生下游令牌
某些架构要求 RS 充当客户端实例,并使用派生的访问令牌用于次级 RS。由于 RS 与发出初始授权请求的实体不同,RS 无法引用或修改现有的授权。因此,RS 需要为其次级 RS 请求或生成一个新的访问令牌。这个内部的次级令牌是在传入访问令牌的上下文中颁发的。
虽然可以使用允许 RS 生成自己的次级令牌的令牌格式(第 2.2 节),但 AS 可以允许 RS 使用与原始客户端实例请求主访问令牌相同的过程来请求此次级访问令牌。由于从 GNAP 的角度来看,RS 是作为自己的客户端实例行事,因此此过程使用与客户端实例请求相同的授权端点、请求结构和响应结构。
+--------+ +-------+ +------+ +-------+
| Client +--(1)->| RS1 | | AS | | RS2 |
|Instance| | +--(2)->| | | |
| | | |<-(3)--+ | | |
| | | | +------+ | |
| | | | | |
| | | +-----------(4)------->| |
| | | |<----------(5)--------+ |
| |<-(6)--+ | | |
+--------+ +-------+ +-------+
1. 客户端实例使用访问令牌调用 RS1。
2. RS1 向 AS 出示该令牌,以获取用于 RS2 的派生令牌。RS1 表明它没有能力与 RO 交互。注意,RS1 使用自己的密钥对其请求进行签名,而不是令牌的密钥或客户端实例的密钥。
3. AS 向 RS1 返回一个用于 RS2 的派生令牌。
4. RS1 使用来自 (3) 的令牌调用 RS2。
5. RS2 满足来自 RS1 的调用。
6. RS1 满足来自原始客户端实例的调用。
如果 RS 需要从出示给它的令牌派生一个令牌,它可以通过发出 [GNAP] 中描述的令牌请求,并在 "existing_access_token" 字段中出示现有访问令牌的值来向 AS 请求一个。
由于 RS 是作为客户端实例行事,RS 必须 在 client 字段中使用自己的密钥标识自己,并像任何客户端实例一样对请求进行签名,如第 3.2 节所述。AS 必须 确定所出示的令牌适合用于发出令牌链式请求的 RS。
POST /tx HTTP/1.1
Host: server.example.com
Content-Type: application/json
Detached-JWS: ejy0...
{
"access_token": {
"access": [
{
"actions": [
"read",
"write",
"dolphin"
],
"locations": [
"https://server.example.net/",
"https://resource.local/other"
],
"datatypes": [
"metadata",
"images"
]
},
"dolphin-metadata"
]
},
"client": "7C7C4AZ9KHRS6X63AJAO",
"existing_access_token": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0"
}
AS 响应一个用于下游 RS2 的令牌,如 [GNAP] 所述。下游 RS2 可以根据需要为调用更多的 RS 重复此过程。
5. IANA 考虑事项
IANA 已向现有注册表添加值,并在 "授权协商与授权协议 (GNAP)" 注册组下创建了五个注册表。
5.1. 知名 URI
"gnap-as-rs" URI 后缀已注册到 "知名 URI" 注册表,以支持 AS 的 RS 面对发现。
- URI 后缀: gnap-as-rs
- 变更控制者: IETF
- 规范文档: RFC 9767 第 3.1 节
- 状态: 永久
5.2. GNAP 授权请求参数
以下参数在 "GNAP 授权请求参数" 注册表中注册:
- 名称: existing_access_token
- 类型: 字符串
- 参考: RFC 9767 第 4 节
5.3. GNAP 令牌格式
本文档定义了 GNAP 令牌格式,为此 IANA 已创建并维护一个名为 "GNAP 令牌格式" 的新注册表。此注册表的初始值在第 5.3.2 节中给出。未来的分配和对现有分配的修改应通过 "需要规范" 注册政策 [RFC8126] 进行。
指定专家 (DE) 应确保:
- 所有注册都遵循第 5.3.1 节提出的模板。
- 格式的定义与现有参数提供的其他格式足够不同。
- 格式的定义详细指定了访问令牌的格式,足以让 AS 和 RS 能够通信令牌信息。
5.3.1. 注册表模板
- 名称: 格式的名称。
- 状态: 格式是否处于活动使用状态。可能的值是 Active 和 Deprecated。
- 描述: 访问令牌格式的人类可读描述。
- 参考: 定义令牌格式的规范。
5.3.2. 初始注册表内容
+===============+========+====================+============+
| 名称 | 状态 | 描述 | 参考 |
+===============+========+====================+============+
| jwt-signed | Active | JSON Web Token, | [JWT] |
| | | 使用 JWS 签名 | |
+---------------+--------+--------------------+------------+
| jwt-encrypted | Active | JSON Web Token, | [JWT] |
| | | 使用 JWE 加密 | |
+---------------+--------+--------------------+------------+
| macaroon | Active | Macaroon | [MACAROON] |
+---------------+--------+--------------------+------------+
| biscuit | Active | Biscuit | [BISCUIT] |
+---------------+--------+--------------------+------------+
| zcap | Active | ZCAP | [ZCAPLD] |
+---------------+--------+--------------------+------------+
表 1: GNAP 令牌格式注册表的初始内容
5.4. GNAP 令牌内省请求
本文档定义了 GNAP 令牌内省,为此 IANA 已创建并维护一个名为 "GNAP 令牌内省请求" 的新注册表。此注册表的初始值在第 5.4.2 节中给出。未来的分配和对现有分配的修改应通过 "需要规范" 注册政策 [RFC8126] 进行。
DE 应确保:
- 所有注册都遵循第 5.4.1 节提出的模板。
- 声明的定义与注册表中定义的其他声明足够正交,以避免功能重叠。
- 声明的定义详细指定了声明的语法和语义,足以让 AS 和 RS 能够通信令牌值。
5.4.1. 注册表模板
- 名称: 声明的名称。
- 类型: 声明值的 JSON 数据类型。
- 参考: 定义声明的规范。
5.4.2. 初始注册表内容
下表包含 "GNAP 令牌内省请求" 注册表的初始内容。
+=================+=================+=========================+
| 名称 | 类型 | 参考 |
+=================+=================+=========================+
| access_token | string | RFC 9767 第 3.3 节 |
+-----------------+-----------------+-------------------------+
| proof | string | RFC 9767 第 3.3 节 |
+-----------------+-----------------+-------------------------+
| resource_server | object/string | RFC 9767 第 3.3 节 |
+-----------------+-----------------+-------------------------+
| access | array of | RFC 9767 第 3.3 节 |
| | strings/objects | |
+-----------------+-----------------+-------------------------+
表 2: GNAP 令牌内省请求注册表的初始内容
5.5. GNAP 令牌内省响应
本文档定义了 GNAP 令牌内省,为此 IANA 已创建并维护一个名为 "GNAP 令牌内省响应" 的新注册表。此注册表的初始值在第 5.5.2 节中给出。未来的分配和对现有分配的修改应通过 "需要规范" 注册政策 [RFC8126] 进行。
DE 应确保:
- 所有注册都遵循第 5.5.1 节提出的模板。
- 声明的定义与注册表中定义的其他声明足够正交,以避免功能重叠。
- 声明的定义详细指定了声明的语法和语义,足以让 AS 和 RS 能够通信令牌值。
5.5.1. 注册表模板
- 名称: 声明的名称。
- 类型: 声明值的 JSON 数据类型。
- 参考: 定义声明的规范。
5.5.2. 初始注册表内容
下表包含 "GNAP 令牌内省响应" 注册表的初始内容。
+=============+==========================+=========================+
| 名称 | 类型 | 参考 |
+=============+==========================+=========================+
| active | boolean | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| access | array of strings/objects | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| key | object/string | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| flags | array of strings | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| exp | integer | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| iat | integer | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| nbf | integer | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| aud | string or array of | RFC 9767 第 3.3 节 |
| | strings | |
+-------------+--------------------------+-------------------------+
| sub | string | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| iss | string | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
| instance_id | string | RFC 9767 第 3.3 节 |
+-------------+--------------------------+-------------------------+
表 3: GNAP 令牌内省响应注册表的初始内容
5.6. GNAP 资源集注册请求参数
本文档定义了一种为 GNAP AS 注册资源集的方法,为此 IANA 已创建并维护一个名为 "GNAP 资源集注册请求参数" 的新注册表。此注册表的初始值在第 5.6.2 节中给出。未来的分配和对现有分配的修改应通过 "专家审查" 注册政策 [RFC8126] 进行。
DE 应确保:
- 所有注册都遵循第 5.6.1 节提出的模板。
- 参数的定义与注册表中定义的其他参数足够正交,以避免功能重叠。
- 参数的定义详细指定了参数的语法和语义,足以让 AS 和 RS 能够通信资源集。
5.6.1. 注册表模板
- 名称: 参数的名称。
- 类型: 参数值的 JSON 数据类型。
- 参考: 定义令牌的规范。
5.6.2. 初始注册表内容
下表包含 "GNAP 资源集注册请求参数" 注册表的初始内容。
+==============================+=================+=============+
| 名称 | 类型 | 参考 |
+==============================+=================+=============+
| access | array of | RFC 9767 |
| | strings/objects | 第 3.4 节 |
+------------------------------+-----------------+-------------+
| resource_server | object/string | RFC 9767 |
| | | 第 3.4 节 |
+------------------------------+-----------------+-------------+
| token_formats_supported | array of | RFC 9767 |
| | strings | 第 3.4 节 |
+------------------------------+-----------------+-------------+
| token_introspection_required | boolean | RFC 9767 |
| | | 第 3.4 节 |
+------------------------------+-----------------+-------------+
表 4: GNAP 资源集注册请求参数注册表的初始内容
5.7. GNAP 资源集注册响应参数
本文档定义了一种为 GNAP AS 注册资源集的方法,为此 IANA 已创建并维护一个名为 "GNAP 资源集注册响应参数" 的新注册表。此注册表的初始值在第 5.7.2 节中给出。未来的分配和对现有分配的修改应通过 "专家审查" 注册政策 [RFC8126] 进行。
DE 应确保:
- 所有注册都遵循第 5.7.1 节提出的模板。
- 参数的定义与注册表中定义的其他声明足够正交,以避免功能重叠。
- 参数的定义详细指定了声明的语法和语义,足以让 AS 和 RS 能够通信资源集。
5.7.1. 注册表模板
- 名称: 参数的名称。
- 类型: 参数值的 JSON 数据类型。
- 参考: 定义参数的规范。
5.7.2. 初始注册表内容
下表包含 "GNAP 资源集注册响应参数" 注册表的初始内容。
+========================+========+=========================+
| 名称 | 类型 | 参考 |
+========================+========+=========================+
| resource_reference | string | RFC 9767 第 3.4 节 |
+------------------------+--------+-------------------------+
| instance_id | string | RFC 9767 第 3.4 节 |
+------------------------+--------+-------------------------+
| introspection_endpoint | string | RFC 9767 第 3.4 节 |
+------------------------+--------+-------------------------+
表 5: GNAP 资源集注册响应参数注册表的初始内容
5.8. GNAP RS 面对的发现文档字段
本文档定义了一种 GNAP RS 发现 GNAP AS 的方法,为此 IANA 已创建并维护一个名为 "GNAP RS 面对的发现文档字段" 的新注册表。此注册表的初始值在第 5.8.2 节中给出。未来的分配和对现有分配的修改应通过 "专家审查" 注册政策 [RFC8126] 进行。
DE 应确保:
- 所有注册都遵循第 5.8.1 节提出的模板。
- 字段的定义与注册表中定义的其他字段足够正交,以避免功能重叠。
- 字段的定义详细指定了字段的语法和语义,足以让 RS 能够与 AS 通信。
5.8.1. 注册表模板
- 名称: 字段的名称。
- 类型: 字段值的 JSON 数据类型。
- 参考: 定义字段的规范。
5.8.2. 初始注册表内容
下表包含 "GNAP RS 面对的发现文档字段" 注册表的初始内容。
+================================+==========+=============+
| 名称 | 类型 | 参考 |
+================================+==========+=============+
| introspection_endpoint | string | RFC 9767 |
| | | 第 3.1 节 |
+--------------------------------+----------+-------------+
| token_formats_supported | array of | RFC 9767 |
| | strings | 第 3.1 节 |
+--------------------------------+----------+-------------+
| resource_registration_endpoint | string | RFC 9767 |
| | | 第 3.1 节 |
+--------------------------------+----------+-------------+
| grant_request_endpoint | string | RFC 9767 |
| | | 第 3.1 节 |
+--------------------------------+----------+-------------+
| key_proofs_supported | array of | RFC 9767 |
| | strings | 第 3.1 节 |
+--------------------------------+----------+-------------+
表 6: GNAP RS 面对的发现文档字段注册表的初始内容
5.9. GNAP RS 面对的错误代码
本文档定义了一组 AS 可以返回给 RS 的错误,为此 IANA 已创建并维护一个名为 "GNAP RS 面对的错误代码" 的新注册表。此注册表的初始值在第 5.9.2 节中给出。未来的分配和对现有分配的修改应通过 "需要规范" 注册政策 [RFC8126] 进行。
DE 应确保:
- 所有注册都遵循第 5.9.1 节提出的模板。
- 错误响应与其他错误足够不同,以向客户端实例提供可操作的信息。
- 错误响应的定义指定了返回错误响应的所有条件以及客户端实例的预期操作。
5.9.1. 注册模板
- 错误: 错误的唯一字符串代码。
- 参考: 指定值的文档参考,最好包括可用于检索文档副本的 URI。也可以包括相关章节的指示,但不是必需的。
5.9.2. 初始内容
+=========================+=========================+
| 错误 | 参考 |
+=========================+=========================+
| invalid_request | RFC 9767 第 3.5 节 |
+-------------------------+-------------------------+
| invalid_resource_server | RFC 9767 第 3.5 节 |
+-------------------------+-------------------------+
| invalid_access | RFC 9767 第 3.5 节 |
+-------------------------+-------------------------+
表 7: GNAP RS 面对的错误代码注册表的初始内容
6. 安全考虑事项
除了本文档和 [GNAP] 中的规范性要求外,强烈建议实施者在 GNAP 的实施和部署中考虑以下附加安全考虑事项。
6.1. 传输中的 TLS 保护
GNAP 中通过不受信任的网络连接进行的所有请求都必须按照 [BCP195] 概述通过 TLS 进行,以保护请求和响应的内容免受攻击者的操纵和拦截。这包括从客户端实例到 RS 的所有请求,以及从 RS 到 AS 的所有请求。
6.2. 令牌验证
RS 有责任以与其部署一致的方式验证传入的访问令牌。对于自包含的无状态令牌,例如第 2.2 节中描述的令牌,这包括验证令牌的签名并确保相关字段和结果适合正在进行的请求等操作。对于引用式令牌或对 RS 不透明的令牌,可以使用令牌内省 RS 面向 API 来提供有关令牌状态的更新信息,如第 3.3 节所述。
RS 需要验证令牌:
- 是否针对此 RS(受众限制)
- 是否使用令牌的适当密钥出示(另见第 6.4 节)
- 是否标识了访问资源的适当主体(通常是授权令牌颁发的资源所有者)
- 是否由此资源的受信任 AS 签发
即使密钥证明机制必须覆盖令牌的值,仅验证密钥证明本身不足以保护对 RS 的请求。如果 RS 仅验证如第 6.4 节所述的出示方法而不验证令牌本身,攻击者可能使用受损的密钥或混淆代理向 RS 发出超出 RO 授权范围的任意调用。
6.3. 缓存令牌验证结果
由于令牌验证可能是一个昂贵的过程,需要密码学操作或对内省服务(如第 3.3 节所述)的网络调用,RS 可能会缓存特定令牌的验证结果。使用缓存的令牌验证结果的权衡为实施者带来了重要的决策空间:依赖缓存的验证结果提高了性能并降低了处理开销,但代价是缓存中信息的实时性和准确性。当 RS 使用缓存值时,攻击者可能出示已撤销的令牌并被 RS 接受。
与任何缓存一样,此缓存的一致性可以通过多种方式管理。最简单的方法之一是管理缓存的生命周期,以平衡性能和安全性。如果缓存时间过长,攻击者就有更大的时间窗口来使用已撤销的令牌。如果窗口过短,使用缓存的好处就会减少。AS 也可能向 RS 发送主动信号以使已撤销的访问令牌失效,尽管此类机制超出了本规范的范围。
6.4. 密钥证明验证
对于密钥绑定的访问令牌,需要在验证令牌本身值的同时验证证明方法,如第 6.2 节所述。验证过程由密钥证明方法定义,如 [GNAP] 第 7.3 节所述。
如果不验证证明方法,攻击者可能在没有访问令牌绑定密钥的情况下使用受损的令牌。
RS 还需要确保证明方法适合与令牌关联的密钥,包括任何算法或标识符的选择。
证明应在对 RS 的每个请求上独立验证,特别是因为调用的各个方面可能有所不同。因此,RS 永远不应缓存一条消息的证明验证结果并将其应用于后续消息。
6.5. 令牌外泄
由于 RS 可以看到令牌值,受损的 RS 可能将该值泄露给攻击者。因此,RS 需要将令牌值作为敏感信息进行保护,并防止其外泄。
这对于持有者令牌和绑定到共享密钥的令牌尤其成问题,因为 RS 拥有使用该令牌创建新的有效请求所需的所有信息。
6.6. RS 对令牌的重复使用
如果访问令牌是持有者令牌,或者 RS 有权访问出示令牌所需的密钥材料,则 RS 可能被诱骗重复使用客户端出示给它的访问令牌。虽然可以构建一个利用此工件作为特性的系统,但更安全的方法是将传入的访问令牌交换为另一个供 RS 使用的上下文令牌,如第 4 节所述。此访问令牌可以绑定到 RS 自己的密钥,并限制为 RS 所需的访问权限,而不是颁发给客户端实例的令牌所关联的完整权限集。
6.7. 令牌格式考虑事项
对于格式化的令牌,令牌的格式可能有其自身的考虑事项,RS 需要在令牌验证过程中遵循任何此类考虑事项。这些考虑事项的应用和范围是特定于格式的,超出了本规范的范围。
6.8. 令牌内容过度共享
访问令牌模型的内容向 RS 披露了访问令牌的上下文和权限信息。无论内容是从令牌本身解析还是在内省响应中发送,都是如此。
很可能每个 RS 不需要知道令牌模型的所有细节,特别是在单个访问令牌可在多个 RS 上使用的系统中。攻击者可能通过仅破坏一个 RS 来获取有关更大系统的信息。通过将可用信息限制为仅与特定 RS 相关的信息,例如使用第 3.3 节定义的有限内省回复,系统可以遵循向每个 RS 最少披露的原则。
6.9. 资源引用
资源引用,如第 3.4 节协议返回的,旨在对 RS 和客户端都是不透明的。然而,由于它们由 AS 控制,AS 可以将任何它想要的内容放入引用值中。如果此值被非预期的方处理,可能会无意中披露系统结构或其他内部细节。此外,此类模式可能导致客户端软件和 RS 依赖于引用值中存在的某些结构,这削弱了 GNAP 系统中不同角色的关注点分离。
为了缓解此问题,AS 应仅对资源引用使用完全随机或加密的值。
6.10. 来自不受信任 AS 的令牌重新签发
攻击者的客户端实例可能向另一个客户端实例签发自己的令牌,充当第二个客户端实例选择信任的 AS。如果令牌是持有者令牌,或者重新签发使用 AS 提供的密钥绑定,目标客户端实例将无法辨别令牌最初是由有效的 AS 签发的。此过程允许攻击者以有效令牌的形式将自己的会话和权限插入到不知情的客户端实例中,该令牌看起来是代表其自己的 RO 颁发给目标客户端实例的。
这种攻击基于目标客户端的错误配置,因为它被配置为从攻击者的 AS 获取令牌,并将这些令牌与目标 RS 一起使用,而目标 RS 与攻击者的 AS 没有关联。然而,由于令牌最终来自受信任的 AS 并使用有效的密钥出示,RS 无法辨别令牌是通过中间人传递的。
为了缓解此问题,RS 可以通过发现或文档发布其与受信任 AS 的关联。因此,正确遵循此关联的客户端将仅直接向受信任的 RS 请求访问令牌。
此外,将持有者令牌和 AS 提供的密钥的使用限制在特定情况下仅高度信任的 AS,可以防止攻击者能够有意将其令牌外泄给不知情的客户端实例。
6.11. 令牌密钥的内省
第 3.3 节定义的内省响应提供了一种方法,让 AS 告诉 RS 验证请求的密钥证明需要什么密钥材料。捕获内省响应可能将这些安全密钥暴露给攻击者。在非对称密码学的情况下,仅暴露公钥,攻击者无法仅基于此结果重用令牌。这可能会泄露关于客户端实例的原本未知的信息。
如果访问令牌绑定到对称密钥,RS 将需要访问完整的密钥值以验证请求的密钥证明,如第 6.4 节所述。然而,将密钥材料披露给 RS 也使 RS 有能力使用该令牌创建新的请求。在这种情况下,RS 面临与持有者令牌类似的令牌外泄和重用风险,如第 6.6 节所述。因此,对称密钥应仅在 RS 被完全信任不会使用出示给它的令牌创建新请求的系统中使用。
6.12. RS 注册和管理
第 3 节中 RS 面向 API 的大多数功能都通过要求 RS 在请求时出示签名密钥的证明来保护,以标识发出调用的 RS,可能还与 AS 特定的访问令牌结合。这种做法允许 AS 对不同 RS 的 API 调用进行差异化响应,例如,仅回答与给定 RS 相关的访问权限的内省调用,而不是访问令牌可能拥有的所有访问权限。
虽然 RS 及其密钥如何被 AS 知晓的方式超出了本规范的范围,但预计常见做法是静态注册 RS,允许其保护特定资源或某些类别的资源。从根本上说,RS 只能提供其服务的资源。然而,恶意的 AS 可能尝试注册一组模仿不同 RS 的资源,以诱骗可用于目标 RS 的访问令牌。如果访问令牌是持有者令牌或绑定到 RS 已知的对称密钥,那么攻击者的 RS 就获得了在其他地方使用该令牌的能力和知识。
在某些生态系统中,RS 及其关联资源的动态注册是可行的。在此类系统中,RS 的身份可以通过访问权限请求的 location 字段中传递的 URI 来传达,从而允许 AS 限制 RS 对更大系统的视图。
7. 隐私考虑事项
7.1. 令牌内容
访问令牌的内容可能包含关于最终用户、RO 或其他方的个人信息。无论内容是从令牌本身解析还是在内省响应中发送,都是如此。
虽然 RS 有时需要这些信息进行处理,但通常情况下,RS 只是顺便接触到这些细节,而不是有意为之。例如,考虑一个客户端,它被颁发了一个可用于医疗和非医疗 API 的访问令牌。如果此访问令牌包含医疗记录号以便于服务医疗 API 的 RS,那么任何非医疗 API 的 RS 也会在此过程中了解到用户的医疗记录号,即使该 API 不需要进行这种关联。
为了缓解此问题,格式化的令牌可以包含针对不同 RS 的独立部分以隔离数据。或者,可以使用令牌内省来限制返回给每个 RS 的数据,如第 3.3 节所定义。
7.2. 通过内省披露令牌使用情况
当 RS 使用内省时,AS 会知悉特定令牌在特定 RS 处被使用。当 RS 是独立系统时,AS 否则不会洞察此操作。这可能导致 AS 通过观察访问了哪些 RS 以及何时访问来了解特定最终用户的模式和操作。
7.3. 将用户映射到 AS
当客户端实例从 RS 接收有关保护 AS 的信息时,该信息可用于推导有关受保护资源的信息,而无需释放资源本身。例如,如果医疗记录由个人 AS 保护,不受信任的客户端可以调用 RS 来发现保护记录的 AS 的位置。由于 AS 与单个 RO 紧密绑定,未经信任和未经授权的客户端软件可以在不访问记录本身的情况下获取有关受保护资源的信息。
8. 参考文献
8.1. 规范性参考文献
[BCP195] Best Current Practice 195,
<https://www.rfc-editor.org/info/bcp195>.
在撰写本文时,此 BCP 包括以下内容:
Moriarty, K. and S. Farrell, "Deprecating TLS 1.0 and TLS
1.1", BCP 195, RFC 8996, DOI 10.17487/RFC8996, March 2021,
<https://www.rfc-editor.org/info/rfc8996>.
Sheffer, Y., Saint-Andre, P., and T. Fossati,
"Recommendations for Secure Use of Transport Layer
Security (TLS) and Datagram Transport Layer Security
(DTLS)", BCP 195, RFC 9325, DOI 10.17487/RFC9325, November
2022, <https://www.rfc-editor.org/info/rfc9325>.
[GNAP] Richer, J., Ed. and F. Imbault, "Grant Negotiation and
Authorization Protocol (GNAP)", RFC 9635,
DOI 10.17487/RFC9635, October 2024,
<https://www.rfc-editor.org/info/rfc9635>.
[JWT] Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token
(JWT)", RFC 7519, DOI 10.17487/RFC7519, May 2015,
<https://www.rfc-editor.org/info/rfc7519>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
Resource Identifier (URI): Generic Syntax", STD 66,
RFC 3986, DOI 10.17487/RFC3986, January 2005,
<https://www.rfc-editor.org/info/rfc3986>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
Interchange Format", STD 90, RFC 8259,
DOI 10.17487/RFC8259, December 2017,
<https://www.rfc-editor.org/info/rfc8259>.
[RFC8792] Watsen, K., Auerswald, E., Farrel, A., and Q. Wu,
"Handling Long Lines in Content of Internet-Drafts and
RFCs", RFC 8792, DOI 10.17487/RFC8792, June 2020,
<https://www.rfc-editor.org/info/rfc8792>.
8.2. 参考性文献
[BISCUIT] Biscuit, "Biscuit Authorization",
<https://www.biscuitsec.org/>.
[MACAROON] Birgisson, A., Politz, J. G., Erlingsson, U., Taly, A.,
Vrable, M., and M. Lentczner, "Macaroons: Cookies with
Contextual Caveats for Decentralized Authorization in the
Cloud", NDSS Symposium 2014, DOI 10.14722/ndss.2014.23212,
February 2014, <https://www.ndss-symposium.org/ndss2014/
ndss-2014-programme/macaroons-cookies-contextual-caveats-
decentralized-authorization-cloud/>.
[RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for
Writing an IANA Considerations Section in RFCs", BCP 26,
RFC 8126, DOI 10.17487/RFC8126, June 2017,
<https://www.rfc-editor.org/info/rfc8126>.
[ZCAPLD] Lemmer-Webber, C., Ed. and M. Sporny, Ed., "Authorization
Capabilities for Linked Data v0.3", W3C Draft Community
Group Report, January 2023,
<https://w3c-ccg.github.io/zcap-spec/>.
致谢
编辑感谢以下人员的评审、反馈、实施和贡献:Aaron Parecki, Adrian Gropper, Andrii Deinega, Annabelle Backman, Dmitry Barinov, Fabien Imbault, Florian Helmschmidt, George Fletcher, Justin Richer, Kathleen Moriarty, Leif Johansson, Mike Varley, Nat Sakimura, Takahiko Kawasaki, and Yaron Sheffer.
此外,编辑希望承认 Aaron Parecki 对本文档内容的巨大贡献。我们感谢他的洞察力、投入和辛勤工作,没有这些,GNAP 就不会发展到今天的样子。
作者地址
Justin Richer (编辑)
Bespoke Engineering
电子邮件: [email protected]
URI: https://bspk.io/
Fabien Imbault
acert.io
电子邮件: [email protected]
URI: https://acert.io/
[文件内容结束]
翻译说明:
- 术语统一: 关键术语如
Access Token
,Resource Server
,Authorization Server
,Client Instance
,Resource Owner
,End User
,Introspection
等,尽量采用行业内通用或 RFC 中文翻译中常见的译法,并在首次出现时标注英文原文。部分难以直译或已有固定译法的术语(如Bearer Token
译为持有者令牌)也遵循惯例。 - 格式保留: 保留了原文的代码块、JSON 结构、表格、章节引用(如
Section 3.1
)等格式,以确保技术准确性。 - 技术准确性: 力求准确传达复杂的技术概念和协议流程,避免因翻译产生歧义。
- 可读性: 在保持技术准确性的前提下,尽量使中文表达流畅自然。