OAuth2 访问令牌中允许使用哪些字符?
What characters are allowed in an OAuth2 access token?
RFC6749 and RFC6750 似乎在 OAuth2 访问令牌中允许使用哪些字符方面存在分歧。
RFC6749(原始OAuth2规范)的Section A.12定义访问令牌格式如下:
A.12. "access_token" Syntax
The "access_token" element is defined in Sections 4.2.2 and 5.1:
access-token = 1*VSCHAR
在ABNF format中,VSCHAR表示:
VSCHAR = %x20-7E
(这基本上就是all printable ASCII characters)
但是,在 RFC6750(处理 OAuth2 不记名令牌的使用)中,Section 2.1 似乎为访问令牌设置了更严格的允许字符子集。
The syntax for Bearer credentials is as follows:
b64token = 1*( ALPHA / DIGIT /
"-" / "." / "_" / "~" / "+" / "/" ) *"="
credentials = "Bearer" 1*SP b64token
这是一组限制性更强的字符,仅包括字母数字、六个特殊字符和用于填充的尾部 =
。
我的问题是:
这些文档中的哪个在控制? RFC6750 是否优先,因为它更严格?
就“野外”的实际实施而言,访问令牌是否始终限于 RFC6750 字符集?
额外问题:有谁知道为什么这两个规范在同一个月发布的关于如此密切相关的主题在访问令牌格式上存在分歧?
好吧,我不是专家,但根据我的工作经验,我可以告诉你,你应该始终尝试使用 RFC6750;它在技术上声明使用 base64 编码的字符串。为什么?因为大多数使用 OAuth 方法的请求都会建议您使用 Authorization HTTP header,而 base64 编码使用安全的 ASCII 字符,这保证了您的 HTTP 请求在(几乎)所有服务器。 Base64 也更容易解析,并且在 JSON 规范内使用也是安全的。
这更有可能回答您的问题 2。
编辑
嗯,根据您提供的链接,这里是他们的摘要:
RFC6749
The OAuth 2.0 authorization framework enables a third-party
application to obtain limited access to an HTTP service, either on
behalf of a resource owner by orchestrating an approval interaction
between the resource owner and the HTTP service, or by allowing the
third-party application to obtain access on its own behalf. This
specification replaces and obsoletes the OAuth 1.0 protocol described
in RFC 5849.
RFC6750
This specification describes how to use bearer tokens in HTTP
requests to access OAuth 2.0 protected resources. Any party in
possession of a bearer token (a "bearer") can use it to get access to
the associated resources (without demonstrating possession of a
cryptographic key). To prevent misuse, bearer tokens need to be
protected from disclosure in storage and in transport.
根据每个规范各自的摘要,很清楚何时应该使用其中一个或另一个。简而言之,当您要提供对 Web 服务的有限访问然后请求身份验证令牌时,请使用 RFC6749。当您要在 Web 服务中请求 Bearer 令牌时,请使用 RFC6750。不记名令牌应始终进入 HTTP 请求的身份验证 header,并且 Base64 字符串可以安全地作为请求的一部分直接传输。
TLDR :授权header遵循RFC2617中定义的基本模式。所以令牌应该是base64编码的。
这由 rfc6750 的以下短语突出显示,
The syntax of the "Authorization" header field for this scheme
follows the usage of the Basic scheme defined in Section 2 of
[RFC2617]
如果你去检查RFC2617,下面是为用户凭据进行base64编码的ABNF。
credentials = "Basic" basic-credentials
basic-credentials = base64-user-pass
但正如 OP 指出的那样,ABNF 被定义为 b64token
,它允许的不仅仅是 base64 编码。因此,在现实世界的实现中,我们可以看到例如 JWT(base64 的 ABNF 和 .
分离)用作不记名令牌。这是可以接受的,因为它属于 b64token
ABNF。
OP 问题的答案,
- 访问令牌可以包含
%x20-7E
范围内的任何字符。不
对此的限制,这就是访问令牌的定义。
- 如果访问令牌是不记名令牌 (token_type=bearer),那么它必须遵循
b64token
AKA token68
。这 使访问令牌有资格放入授权 header。
- RFC6749 定义了访问令牌的格式。 RFC6750 定义了如何使用授权 header 来传输访问令牌。
b64token 对比 token68
b64token
.
的命名似乎有些混乱
经过一番搜索,我发现了 IETF discussions on RFC7235。 RFC7235 定义了 HTTP 身份验证的当前标准(其中也包括 Authorizationheader)
根据这些讨论,b64token
是一种特定的编码。并且有人建议将 b64token
重命名为 token68
。他们进行了此更改,基本上 b64token
指的是 token68
.
Appendix section 解释 token68
关于 HTTP 授权 header,(注意 - 这些是摘录的。转到 link 查看 ABNF 的完整解释)
Authorization = credentials
凭据 = auth-scheme [ 1SP ( token68 / [ ( "," / auth-param )( OWS "," [ OWS auth-param ] ) ] ) ]
token68 = 1( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/ " )"="**
因此,正如我所见,RFC6750 未使用这些命名进行更新(这些定义在编写时正在进行中)。
TL;DR: 标准之间没有冲突。 OAuth 访问令牌可以通常 包含任何可打印的 ASCII 字符,但是 如果 访问令牌是 Bearer 令牌,它必须使用“token64”语法才能成为 HTTP/1.1 合规。
RFC 6749, §1.4 tells us: "An access token is a string" and "usually opaque to the client". §A.12 将其定义为一个或多个可打印的 ASCII 字符([ -~]+
在正则表达式中)。
RFC 6749 定义了获取访问令牌的各种方法,但并不关心如何实际使用访问令牌,而不是说您将它“呈现”给资源服务器,资源服务器必须验证然后接受或拒绝它。
但是 RFC 6749 确实要求授权服务器告诉客户端 令牌类型(另一个字符串),客户端可以使用它来确定 如何 使用访问令牌。
A 令牌类型 字符串是 IANA-registered 类型名称(如 Bearer
或 mac
),或供应商 URL(如 http://oauth.example.org/v1
),尽管 URL 只是一个方便的命名空间标识符,并且不必解析为任何内容。
在大多数部署中,令牌类型将为 Bearer
,其语义在 RFC 6750 中定义。
RFC 6750 定义了三种 方法 (§§2.1–2.3) 来向资源服务器提供 Bearer 访问令牌。 推荐方法(资源服务器必须支持以符合标准)是在HTTP授权header中发送它(§2.1),在这种情况下,令牌必须是“b64token”(正则表达式中的[-a-zA-Z0-9._~+/]+=*
)。
这与 HTTP/1.1 规范所称的“token68”(RFC 7235 §2.1) 相匹配,并且是允许在 HTTP 授权 header 中不加引号使用令牌所必需的. (至于为什么 HTTP/1.1 允许这些确切的字符,归结为与 HTTP/1.0 和基本身份验证标准相关的历史原因,以及当前和历史 HTTP 实现的限制。网络协议是一桩麻烦事。)
“b64token”(aka“token68”)允许通常与 base64 编码一起使用的 ASCII 字符子集,但是(尽管有名称)Bearer 令牌 does not impose any base64 semantics. It's just an opaque string that the client receives from one server and passes on to another. Implementations may assign semantics to it (e.g. JWT),但这超出了 OAuth 或 Bearer 令牌标准。
RFC 6750 没有声明如果与其他两种(不推荐的)方法一起使用,Bearer 访问令牌必须是 b64token,但是考虑到客户端应该能够选择该方法,它不会给它一个非 b64token 令牌很有意义。
其他 OAuth 令牌类型可能不依赖于在 HTTP header 中不加引号传递(或者它们可能根本不使用 HTTP),因此可以自由使用任何可打印的 ASCII 字符。这可能例如对于 not 对客户端不透明的令牌类型很有用;例如,我目前正在处理一个访问令牌响应看起来有点像这样的设置:
{
"access_token": "{\"endpoint\": \"srv8.example.org\", \"session_id\": \"fafc2fd\"}",
"token_type": "http://vendor.example.org/",
"expires_in": 3600,
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA"
}
此处,访问令牌是一个 JSON-encoded 数据结构,客户端必须对其进行操作(根据与供应商令牌类型关联的规则)以访问受保护的资源。
RFC6749 and RFC6750 似乎在 OAuth2 访问令牌中允许使用哪些字符方面存在分歧。
RFC6749(原始OAuth2规范)的Section A.12定义访问令牌格式如下:
A.12. "access_token" Syntax
The "access_token" element is defined in Sections 4.2.2 and 5.1:
access-token = 1*VSCHAR
在ABNF format中,VSCHAR表示:
VSCHAR = %x20-7E
(这基本上就是all printable ASCII characters)
但是,在 RFC6750(处理 OAuth2 不记名令牌的使用)中,Section 2.1 似乎为访问令牌设置了更严格的允许字符子集。
The syntax for Bearer credentials is as follows:
b64token = 1*( ALPHA / DIGIT /
"-" / "." / "_" / "~" / "+" / "/" ) *"="
credentials = "Bearer" 1*SP b64token
这是一组限制性更强的字符,仅包括字母数字、六个特殊字符和用于填充的尾部 =
。
我的问题是:
这些文档中的哪个在控制? RFC6750 是否优先,因为它更严格?
就“野外”的实际实施而言,访问令牌是否始终限于 RFC6750 字符集?
额外问题:有谁知道为什么这两个规范在同一个月发布的关于如此密切相关的主题在访问令牌格式上存在分歧?
好吧,我不是专家,但根据我的工作经验,我可以告诉你,你应该始终尝试使用 RFC6750;它在技术上声明使用 base64 编码的字符串。为什么?因为大多数使用 OAuth 方法的请求都会建议您使用 Authorization HTTP header,而 base64 编码使用安全的 ASCII 字符,这保证了您的 HTTP 请求在(几乎)所有服务器。 Base64 也更容易解析,并且在 JSON 规范内使用也是安全的。
这更有可能回答您的问题 2。
编辑
嗯,根据您提供的链接,这里是他们的摘要:
RFC6749
The OAuth 2.0 authorization framework enables a third-party
application to obtain limited access to an HTTP service, either on
behalf of a resource owner by orchestrating an approval interaction
between the resource owner and the HTTP service, or by allowing the
third-party application to obtain access on its own behalf. This
specification replaces and obsoletes the OAuth 1.0 protocol described in RFC 5849.
RFC6750
This specification describes how to use bearer tokens in HTTP
requests to access OAuth 2.0 protected resources. Any party in
possession of a bearer token (a "bearer") can use it to get access to the associated resources (without demonstrating possession of a
cryptographic key). To prevent misuse, bearer tokens need to be
protected from disclosure in storage and in transport.
根据每个规范各自的摘要,很清楚何时应该使用其中一个或另一个。简而言之,当您要提供对 Web 服务的有限访问然后请求身份验证令牌时,请使用 RFC6749。当您要在 Web 服务中请求 Bearer 令牌时,请使用 RFC6750。不记名令牌应始终进入 HTTP 请求的身份验证 header,并且 Base64 字符串可以安全地作为请求的一部分直接传输。
TLDR :授权header遵循RFC2617中定义的基本模式。所以令牌应该是base64编码的。
这由 rfc6750 的以下短语突出显示,
The syntax of the "Authorization" header field for this scheme follows the usage of the Basic scheme defined in Section 2 of [RFC2617]
如果你去检查RFC2617,下面是为用户凭据进行base64编码的ABNF。
credentials = "Basic" basic-credentials
basic-credentials = base64-user-pass
但正如 OP 指出的那样,ABNF 被定义为 b64token
,它允许的不仅仅是 base64 编码。因此,在现实世界的实现中,我们可以看到例如 JWT(base64 的 ABNF 和 .
分离)用作不记名令牌。这是可以接受的,因为它属于 b64token
ABNF。
OP 问题的答案,
- 访问令牌可以包含
%x20-7E
范围内的任何字符。不 对此的限制,这就是访问令牌的定义。 - 如果访问令牌是不记名令牌 (token_type=bearer),那么它必须遵循
b64token
AKAtoken68
。这 使访问令牌有资格放入授权 header。 - RFC6749 定义了访问令牌的格式。 RFC6750 定义了如何使用授权 header 来传输访问令牌。
b64token 对比 token68
b64token
.
经过一番搜索,我发现了 IETF discussions on RFC7235。 RFC7235 定义了 HTTP 身份验证的当前标准(其中也包括 Authorizationheader)
根据这些讨论,b64token
是一种特定的编码。并且有人建议将 b64token
重命名为 token68
。他们进行了此更改,基本上 b64token
指的是 token68
.
Appendix section 解释 token68
关于 HTTP 授权 header,(注意 - 这些是摘录的。转到 link 查看 ABNF 的完整解释)
Authorization = credentials
凭据 = auth-scheme [ 1SP ( token68 / [ ( "," / auth-param )( OWS "," [ OWS auth-param ] ) ] ) ]
token68 = 1( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/ " )"="**
因此,正如我所见,RFC6750 未使用这些命名进行更新(这些定义在编写时正在进行中)。
TL;DR: 标准之间没有冲突。 OAuth 访问令牌可以通常 包含任何可打印的 ASCII 字符,但是 如果 访问令牌是 Bearer 令牌,它必须使用“token64”语法才能成为 HTTP/1.1 合规。
RFC 6749, §1.4 tells us: "An access token is a string" and "usually opaque to the client". §A.12 将其定义为一个或多个可打印的 ASCII 字符([ -~]+
在正则表达式中)。
RFC 6749 定义了获取访问令牌的各种方法,但并不关心如何实际使用访问令牌,而不是说您将它“呈现”给资源服务器,资源服务器必须验证然后接受或拒绝它。
但是 RFC 6749 确实要求授权服务器告诉客户端 令牌类型(另一个字符串),客户端可以使用它来确定 如何 使用访问令牌。
A 令牌类型 字符串是 IANA-registered 类型名称(如 Bearer
或 mac
),或供应商 URL(如 http://oauth.example.org/v1
),尽管 URL 只是一个方便的命名空间标识符,并且不必解析为任何内容。
在大多数部署中,令牌类型将为 Bearer
,其语义在 RFC 6750 中定义。
RFC 6750 定义了三种 方法 (§§2.1–2.3) 来向资源服务器提供 Bearer 访问令牌。 推荐方法(资源服务器必须支持以符合标准)是在HTTP授权header中发送它(§2.1),在这种情况下,令牌必须是“b64token”(正则表达式中的[-a-zA-Z0-9._~+/]+=*
)。
这与 HTTP/1.1 规范所称的“token68”(RFC 7235 §2.1) 相匹配,并且是允许在 HTTP 授权 header 中不加引号使用令牌所必需的. (至于为什么 HTTP/1.1 允许这些确切的字符,归结为与 HTTP/1.0 和基本身份验证标准相关的历史原因,以及当前和历史 HTTP 实现的限制。网络协议是一桩麻烦事。)
“b64token”(aka“token68”)允许通常与 base64 编码一起使用的 ASCII 字符子集,但是(尽管有名称)Bearer 令牌 does not impose any base64 semantics. It's just an opaque string that the client receives from one server and passes on to another. Implementations may assign semantics to it (e.g. JWT),但这超出了 OAuth 或 Bearer 令牌标准。
RFC 6750 没有声明如果与其他两种(不推荐的)方法一起使用,Bearer 访问令牌必须是 b64token,但是考虑到客户端应该能够选择该方法,它不会给它一个非 b64token 令牌很有意义。
其他 OAuth 令牌类型可能不依赖于在 HTTP header 中不加引号传递(或者它们可能根本不使用 HTTP),因此可以自由使用任何可打印的 ASCII 字符。这可能例如对于 not 对客户端不透明的令牌类型很有用;例如,我目前正在处理一个访问令牌响应看起来有点像这样的设置:
{
"access_token": "{\"endpoint\": \"srv8.example.org\", \"session_id\": \"fafc2fd\"}",
"token_type": "http://vendor.example.org/",
"expires_in": 3600,
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA"
}
此处,访问令牌是一个 JSON-encoded 数据结构,客户端必须对其进行操作(根据与供应商令牌类型关联的规则)以访问受保护的资源。