Proof Key for Code Exchange by OAuth Public Clients

摘要

使用授权码授权的OAuth 2.0公共客户端容易受到授权码截取攻击。本规范描述了通过使用代码交换证明密钥(PKCE,发音为“pixy”)来减轻这种威胁的攻击和技术。

OAuth 2.0 public clients utilizing the Authorization Code Grant are susceptible to the authorization code interception attack. This specification describes the attack as well as a technique to mitigate against the threat through the use of Proof Key for Code Exchange(PKCE, pronounced “pixy”).

1. 简介(Introduction)

OAuth 2.0 [RFC6749]公共客户端容易受到授权码截取攻击。

在这种攻击中,攻击者拦截来自不受传输层安全(Transport Layer Security, TLS)保护的通信路径内的授权端点返回的授权代码,例如客户端操作系统内的应用程序间通信。

一旦攻击者获得了对授权代码的访问权,它就可以使用它来获得访问令牌。

图1显示了攻击的图形。 在步骤(1)中,运行在终端设备上的本地应用程序,如智能手机,通过浏览器/操作系统发出OAuth 2.0授权请求。在这种情况下,重定向端点URI通常使用自定义URI方案。 第(1)步是通过一个安全的API发生的,不能被拦截,尽管它可能在高级攻击场景中被观察到。 然后,该请求被转发到步骤(2)中的OAuth 2.0授权服务器。 因为OAuth要求使用TLS,所以这种通信受到TLS的保护,不能被拦截。 授权服务器在步骤(3)中返回授权代码。 在步骤(4)中,授权码会通过步骤(1)中提供的重定向端点URI返回给请求者。

请注意,除了合法的OAuth 2.0应用程序外,恶意应用程序有可能将自己注册为自定义方案的处理程序。 一旦这样做,恶意应用程序现在能够拦截步骤(4)的授权代码。 这使得攻击者可以在步骤(5)和(6)中分别请求和获得一个访问令牌。

image.png
要让这种攻击起作用,必须具备若干先决条件:

  1. 攻击者设法在客户端设备上注册一个恶意应用程序,并注册另一个应用程序也使用的自定义URI方案。操作系统必须允许多个应用程序注册自定义URI方案。

  2. 使用的是OAuth 2.0授权码授予。

3.攻击者可以访问OAuth 2.0 [RFC6749]“ client_id”和“ client_secret”(如果已设置)。 所有OAuth 2.0本机应用程序客户端实例都使用相同的“ client_id”。 客户端二进制应用程序中设置的机密不能视为机密。

4.满足以下条件之一:
4 a.攻击者(通过安装的应用程序)只能观察来自授权端点的响应。当“code_challenge_method”的值是“plain”时,只会减轻这种攻击。
4b. 一个更复杂的攻击场景允许攻击者观察对授权端点的请求(除了响应)。 然而,攻击者不能作为中间人。 这是由操作系统中的http日志信息泄露造成的。 为了缓解这种情况,”code_challenge_method “值必须设置为 “S256 “或由加密安全的 “code_challenge_method “扩展定义的值。

虽然这是一个很长的先决条件列表,但所描述的攻击已经在未受控制的环境下观察到,必须在OAuth 2.0部署中加以考虑。虽然OAuth 2.0威胁模型([RFC6819]第4.4.1节)描述了缓解技术,但不幸的是,它们并不适用,因为它们依赖于每个客户端实例秘密或每个客户端实例重定向URI。

为了减轻这种攻击,这个扩展利用了一个动态创建的密码学随机密钥,称为 “code verifier“。 为每个授权请求创建一个独特的代码验证器,它的转换值,称为 “code challenge“,被发送到授权服务器以获得授权代码。 然后,获得的授权代码被发送到带有 “code verifier“的令牌端点,服务器将其与之前收到的请求代码进行比较,从而可以进行客户拥有 “code verifier “的证明。 这可以作为缓解措施,因为攻击者不会知道这个一次性密钥,因为它是通过TLS发送的,不能被截获。


OAuth 2.0 [RFC6749] public clients are susceptible to the authorization code interception attack.

In this attack, the attacker intercepts the authorization code returned from the authorization endpoint within a communication path not protected by Transport Layer Security (TLS), such as inter-application communication within the client’s operating system.

Once the attacker has gained access to the authorization code, it can use it to obtain the access token.

Figure 1 shows the attack graphically. In step (1), the native application running on the end device, such as a smartphone, issues an OAuth 2.0 Authorization Request via the browser/operating system.The Redirection Endpoint URI in this case typically uses a custom URI scheme. Step (1) happens through a secure API that cannot be intercepted, though it may potentially be observed in advanced attack scenarios. The request then gets forwarded to the OAuth 2.0 authorization server in step (2). Because OAuth requires the use of TLS, this communication is protected by TLS and cannot be intercepted. The authorization server returns the authorization code in step (3). In step (4), the Authorization Code is returned to the requester via the Redirection Endpoint URI that was provided in step (1).

Note that it is possible for a malicious app to register itself as a handler for the custom scheme in addition to the legitimate OAuth 2.0 app. Once it does so, the malicious app is now able to intercept the authorization code in step (4). This allows the attacker to request and obtain an access token in steps (5) and (6), respectively.

image.png

A number of pre-conditions need to hold for this attack to work:

  1. The attacker manages to register a malicious application on the client device and registers a custom URI scheme that is also used by another application. The operating systems must allow a custom URI scheme to be registered by multiple applications.

  2. The OAuth 2.0 authorization code grant is used.

  3. The attacker has access to the OAuth 2.0 [RFC6749] “client_id” and “client_secret” (if provisioned). All OAuth 2.0 native app client-instances use the same “client_id”. Secrets provisioned in client binary applications cannot be considered confidential.

  4. Either one of the following condition is met: 4a. The attacker (via the installed application) is able to observe only the responses from the authorization endpoint. When “code_challenge_method” value is “plain”, only this attack is mitigated. 4b. A more sophisticated attack scenario allows the attacker to observe requests (in addition to responses) to the authorization endpoint. The attacker is, however, not able to act as a man in the middle. This was caused by leaking http log information in the OS. To mitigate this, “code_challenge_method” value must be set either to “S256” or a value defined by a cryptographically secure “code_challenge_method” extension.

While this is a long list of pre-conditions, the described attack has been observed in the wild and has to be considered in OAuth 2.0 deployments. While the OAuth 2.0 threat model (Section 4.4.1 of [RFC6819]) describes mitigation techniques, they are, unfortunately, not applicable since they rely on a per-client instance secret or a per-client instance redirect URI.

To mitigate this attack, this extension utilizes a dynamically created cryptographically random key called “code verifier”. A unique code verifier is created for every authorization request, and its transformed value, called “code challenge”, is sent to the authorization server to obtain the authorization code. The authorization code obtained is then sent to the token endpoint with the “code verifier”, and the server compares it with the previously received request code so that it can perform the proof of possession of the “code verifier” by the client. This works as the mitigation since the attacker would not know this one-time key, since it is sent over TLS and cannot be intercepted.

1.1 协议流(Protocol Flow)

image.png
本规范为OAuth 2.0授权和访问令牌请求增加了额外的参数,以抽象的形式显示在图2中。

A. 客户端创建并记录一个名为 “code_verifier “的秘密,并得出一个转换版本 “t(code_verifier)”(称为 “code_challenge“),在OAuth 2.0授权请求中与转换方法 “t_m “一起发送。

B.授权端点照常响应,但记录“ t(code_verifier)”和转换方法。

C.然后,客户端照常在访问令牌请求中发送授权代码,但包括在(A)处生成的“ code_verifier”秘密。

D. 授权服务器对 “code_verifier “进行转换,并将其与(B)中的 “t(code_verifier) “相比较。 如果两者不相等,则拒绝访问。

在(B)处截获授权码的攻击者无法将其兑换成访问令牌,因为他们没有掌握 “code_verifier “秘密。


This specification adds additional parameters to the OAuth 2.0 Authorization and Access Token Requests, shown in abstract form in Figure 2.

A. The client creates and records a secret named the “code_verifier” and derives a transformed version “t(code_verifier)” (referred to as the “code_challenge”), which is sent in the OAuth 2.0 Authorization Request along with the transformation method “t_m”.

B. The Authorization Endpoint responds as usual but records “t(code_verifier)” and the transformation method.

C. The client then sends the authorization code in the Access Token Request as usual but includes the “code_verifier” secret generated at (A).

D. The authorization server transforms “code_verifier” and compares it to “t(code_verifier)” from (B). Access is denied if they are not equal.

An attacker who intercepts the authorization code at (B) is unable to redeem it for an access token, as they are not in possession of the “code_verifier” secret.

2. 符号约定(Notational Conventions)

3. 术语(Terminology)

除了OAuth 2.0 [RFC6749]中定义的术语外,本规范还定义了以下术语:

code verifier
一种用于将授权请求与令牌请求相关联的密码随机字符串。

code challenge
来自授权请求中发送的代码验证程序的质询,将在以后进行验证。

code challenge method
用于推导code challenge的方法。

Base64url Encoding
使用[RFC4648]第5节中定义的URL和文件名安全字符集进行Base64编码,并省略所有结尾的’=’字符([RFC4648] 3.2节所允许),并且不包含任何换行符,空格 或其他其他字符。 (有关不进行填充而实现base64url编码的说明,请参阅附录A。)


In addition to the terms defined in OAuth 2.0 [RFC6749], this specification defines the following terms:

code verifier
A cryptographically random string that is used to correlate the authorization request to the token request.

code challenge A challenge derived from the code verifier that is sent in the authorization request, to be verified against later.

code challenge method A method that was used to derive code challenge.

Base64url Encoding Base64 encoding using the URL- and filename-safe character set defined in Section 5 of [RFC4648], with all trailing ‘=’ characters omitted (as permitted by Section 3.2 of [RFC4648]) and without the inclusion of any line breaks, whitespace, or other additional characters. (See Appendix A for notes on implementing base64url encoding without padding.)

3.1. 缩略语( Abbreviations)

ABNF Augmented Backus-Naur Form(增强Backus-Naur形式)
Authz Authorization(授权)
PKCE Proof Key for Code Exchange(代码交换的证明密钥)
MITM Man-in-the-middle(中间人)
MTI Mandatory To Implement(强制实施)

4. 协议(Protocol)

4.1 客户端创建一个代码验证器(Client Creates a Code Verifier)

客户端首先为每个OAuth 2.0 [RFC6749]授权请求创建一个代码验证器“code_verifier”,如下所示:

codeverifier = 高熵加密随机STRING,使用非保留字符[A-Z] / [a-z] / [0-9] / “-“ / “. / ““ / “~”,最小长度为43个字符,最大长度为128个字符,来自[RFC3986]的第2.3节。

code_verifier的增强Backus-Naur形式如下:

code-verifier = 43*128unreserved unreserved = ALPHA / DIGIT / “-“ / “.” / “_” / “~”
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39

注意:代码验证者应该具有足够的熵,以使其无法猜出该值。 建议使用合适的随机数生成器的输出来创建32个八位位组的序列。 然后,对八位字节序列进行base64url编码,以生成43个八位字节的URL安全字符串,以用作代码验证程序。


The client first creates a code verifier, “code_verifier”, for each OAuth 2.0 [RFC6749] Authorization Request, in the following manner:

codeverifier = high-entropy cryptographic random STRING using the unreserved characters [A-Z] / [a-z] / [0-9] / “-“ / “.” / ““ / “~” from Section 2.3 of [RFC3986], with a minimum length of 43 characters and a maximum length of 128 characters.

ABNF for “code_verifier” is as follows.

code-verifier = 43*128unreserved unreserved = ALPHA / DIGIT / “-“ / “.” / “_” / “~” ALPHA = %x41-5A / %x61-7A DIGIT = %x30-39

NOTE: The code verifier SHOULD have enough entropy to make it impractical to guess the value. It is RECOMMENDED that the output of a suitable random number generator be used to create a 32-octet sequence. The octet sequence is then base64url-encoded to produce a 43-octet URL safe string to use as the code verifier.

4.2 客户端创建Code Challenge(Client Creates the Code Challenge)

然后,客户端通过在代码验证器上使用以下转换之一来创建从代码验证器派生的code challenge:

plain
code_challenge = code_verifier

S256
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

如果客户端能够使用“ S256”,则它必须使用“ S256”,因为“ S256”是服务器上强制实施的(MTI)。 仅当客户端由于某些技术原因不支持“ S256”并且通过带外配置知道服务器支持“plain”时,才允许客户端使用“plain”。

plain转换是为了与现有的部署相兼容,并用于不能使用S256转换的受限环境。

code_challenge的增强Backus-Naur形式如下:

code-challenge = 43*128unreserved


The client then creates a code challenge derived from the code verifier by using one of the following transformations on the code verifier: plain
code_challenge = code_verifier

S256 code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

If the client is capable of using “S256”, it MUST use “S256”, as “S256” is Mandatory To Implement (MTI) on the server. Clients are permitted to use “plain” only if they cannot support “S256” for some technical reason and know via out-of-band configuration that the server supports “plain”.

The plain transformation is for compatibility with existing deployments and for constrained environments that can’t use the S256 transformation.

ABNF for “code_challenge” is as follows.

code-challenge = 43*128unreserved

4.3 客户端发送Code Challenge通过授权请求(Client Sends the Code Challenge with the Authorization Request)

客户端将code challenge作为OAuth 2.0授权请求([RFC6749]第4.1.1节)的一部分发送,并使用以下附加参数:

code_challenge
必需。 Code challenge.

code_challenge_method
可选,,若未在请求中指定,默认为 “plain”。 可选 “S256” 或”plain”。


The client sends the code challenge as part of the OAuth 2.0 Authorization Request (Section 4.1.1 of [RFC6749]) using the following additional parameters:

code_challenge REQUIRED. Code challenge.

code_challenge_method OPTIONAL, defaults to “plain” if not present in the request. Code verifier transformation method is “S256” or “plain”.

4.4 服务返回代码(Server Returns the Code)

当服务器在授权响应中发出授权码时,它必须将 “code_challenge “和 “code_challenge_method “值与授权码联系起来,以便以后可以验证。

通常,“ code_challenge”和“ code_challenge_method”值以加密形式存储在“code”本身中,但也可以存储在与该code关联的服务器上。 服务器不得以其他实体可以提取的形式在客户端请求中包含“code_challenge”值。

服务器用于将“ code_challenge”与发出的“ code”相关联的确切方法超出了本规范的范围。


When the server issues the authorization code in the authorization response, it MUST associate the “code_challenge” and “code_challenge_method” values with the authorization code so it can be verified later.

Typically, the “code_challenge” and “code_challenge_method” values are stored in encrypted form in the “code” itself but could alternatively be stored on the server associated with the code. The server MUST NOT include the “code_challenge” value in client requests in a form that other entities can extract.

The exact method that the server uses to associate the “code_challenge” with the issued “code” is out of scope for this specification.

4.4.1 错误响应(Error Response)

如果服务器要求OAuth公共客户端进行代码交换证明密钥(PKCE),并且客户端未在请求中发送“code_challenge”,则授权端点务必返回授权错误响应,并将“error”值设置为“ invalid_request” 。 “ error_description”或“ error_uri”的响应应解释错误的性质,例如,code challenge必需

如果支持PKCE的服务器不支持请求的转换,则授权端点必须返回授权错误响应,并将“error”值设置为“invalid_request”。 “ error_description”或“ error_uri”的响应应说明错误的性质,例如,不支持变换算法。


If the server requires Proof Key for Code Exchange (PKCE) by OAuth public clients and the client does not send the “code_challenge” in the request, the authorization endpoint MUST return the authorization error response with the “error” value set to “invalid_request”. The “error_description” or the response of “error_uri” SHOULD explain the nature of error, e.g., code challenge required.

If the server supporting PKCE does not support the requested transformation, the authorization endpoint MUST return the authorization error response with “error” value set to “invalid_request”. The “error_description” or the response of “error_uri” SHOULD explain the nature of error, e.g., transform algorithm not supported.

4.5. 客户端发送授权码和Code Verifier到令牌端点(Client Sends the Authorization Code and the Code Verifier to the Token Endpoint)

客户端收到授权码后,将访问令牌请求发送到令牌端点。 除了OAuth 2.0访问令牌请求([RFC6749]的4.1.3节)中定义的参数外,它还会发送以下参数:
code_verifier
REQUIRED. Code verifier

当授权码发出时,”code_challenge_method “被绑定到授权码上。 这是令牌端点必须用来验证 “code_verifier “的方法。


Upon receipt of the Authorization Code, the client sends the Access Token Request to the token endpoint. In addition to the parameters defined in the OAuth 2.0 Access Token Request (Section 4.1.3 of [RFC6749]), it sends the following parameter: code_verifier REQUIRED. Code verifier

The “code_challenge_method” is bound to the Authorization Code when the Authorization Code is issued. That is the method that the token endpoint MUST use to verify the “code_verifier”.

4.6 服务器在返回令牌之前验证code_verifier(Server Verifies code_verifier before Returning the Tokens)

在令牌端点收到请求后,服务器通过从收到的 “code_verifier “中计算code challenge并与先前关联的 “code_challenge “进行比较来验证它,在此之前先根据客户指定的 “code_challenge_method “方法进行转换。

如果第4.3节中的“ code_challenge_method”为“ S256”,则接收到的“ code_verifier”将由SHA-256进行散列,以base64url编码,然后与“ code_challenge”进行比较,即:


Upon receipt of the request at the token endpoint, the server verifies it by calculating the code challenge from the received “code_verifier” and comparing it with the previously associated “code_challenge”, after first transforming it according to the “code_challenge_method” method specified by the client.

If the “code_challenge_method” from Section 4.3 was “S256”, the received “code_verifier” is hashed by SHA-256, base64url-encoded, and then compared to the “code_challenge”, i.e.:

5. 兼容性(Compatibility)

本规范的服务器实现可以接受不实现该扩展的OAuth2.0客户端。 如果在授权请求中没有收到来自客户端的 “code_verifier“,支持向后兼容的服务器将恢复到没有该扩展的OAuth 2.0 [RFC6749]协议。

由于OAuth 2.0 [RFC6749]的服务器响应在本规范中没有变化,本规范的客户端实现不需要知道服务器是否实施了本规范,应该向所有服务器发送第4节中定义的附加参数。


Server implementations of this specification MAY accept OAuth2.0 clients that do not implement this extension. If the “code_verifier” is not received from the client in the Authorization Request, servers supporting backwards compatibility revert to the OAuth 2.0 [RFC6749] protocol without this extension.

As the OAuth 2.0 [RFC6749] server responses are unchanged by this specification, client implementations of this specification do not need to know if the server has implemented this specification or not and SHOULD send the additional parameters as defined in Section 4 to all servers.

6. IANA注意事项(IANA Considerations)

IANA已根据本文档进行了以下注册。


IANA has made the following registrations per this document.

6.1 OAuth参数注册表(OAuth Parameters Registry)

本规范在OAuth 2.0 [RFC6749]中定义的IANA“ OAuth参数”注册表中注册了以下参数。

o Parameter name: code_verifier
o Parameter usage location: token request
o Change controller: IESG
o Specification document(s): RFC 7636 (this document)

o Parameter name: code_challenge
o Parameter usage location: authorization request
o Change controller: IESG
o Specification document(s): RFC 7636 (this document)

o Parameter name: code_challenge_method
o Parameter usage location: authorization request
o Change controller: IESG
o Specification document(s): RFC 7636 (this document)

This specification registers the following parameters in the IANA “OAuth Parameters” registry defined in OAuth 2.0 [RFC6749].

6.2 PKCE Code Challenge方法注册(PKCE Code Challenge Method Registry)

该规范建立了“ PKCE Code Challenge Methods”注册表。 新注册表应该是“ OAuth Parameters”注册表的子注册表。

额外的 “code_challenge_method “类型用于授权端点是使用规范要求的策略[RFC5226]注册的,其中包括由一个或多个指定专家(DE)审查该请求。 指定专家将确保在oauth-ext-review@ietf.org 邮件列表上对该请求进行至少两周的审查,并且在他们对该请求做出回应之前,该列表上的任何讨论都会趋于一致。 为了允许在发布前分配价值,指定专家可以在他们确信将发布可接受的规范时批准注册。

在oauth-ext-review@ietf.org 邮件列表上的注册请求和讨论应该使用一个合适的主题,例如 “请求PKCE code_challenge_method”

指定专家在评估注册请求时应考虑邮件列表上的讨论,以及挑战方法的整体安全属性。 新方法不应该在向授权端点的请求中披露code_verifier的值。 拒绝应该包括一个解释,如果适用的话,应该包括如何使请求成功的建议。


This specification establishes the “PKCE Code Challenge Methods” registry. The new registry should be a sub-registry of the “OAuth Parameters” registry.

Additional “code_challenge_method” types for use with the authorization endpoint are registered using the Specification Required policy [RFC5226], which includes review of the request by one or more Designated Experts (DEs). The DEs will ensure that there is at least a two-week review of the request on the oauth-ext- review@ietf.org mailing list and that any discussion on that list converges before they respond to the request. To allow for the allocation of values prior to publication, the Designated Expert(s) may approve registration once they are satisfied that an acceptable specification will be published.

Registration requests and discussion on the oauth-ext-review@ietf.org mailing list should use an appropriate subject, such as “Request for PKCE code_challenge_method: example”).

The Designated Expert(s) should consider the discussion on the mailing list, as well as the overall security properties of the challenge method when evaluating registration requests. New methods should not disclose the value of the code_verifier in the request to the Authorization endpoint. Denials should include an explanation and, if applicable, suggestions as to how to make the request successful.

6.2.1 注册模板(Registration Template)

Code Challenge方法参数名:
要求的名称(例如“example”)。 因为此规范的核心目标是使表示形式紧凑,所以建议名称简短-不超过8个字符,没有充分的理由。 该名称区分大小写。 名称不能以不区分大小写的方式与其他注册名称匹配,除非指定专家指出有充分的理由在这种特殊情况下允许例外。

Change 控制器:
对于标准跟踪rfc,请注明“IESG”。对于其他人,给出责任方的名称。其他细节(例如,邮政地址、电子邮件地址和主页URI)也可能包括在内。

规范文档(s):
对指定参数的文档的引用,最好包括可用于检索文档副本的URI。相关章节的指示也可能包括在内,但不是必需的。


Code Challenge Method Parameter Name: The name requested (e.g., “example”). Because a core goal of this specification is for the resulting representations to be compact, it is RECOMMENDED that the name be short — not to exceed 8 characters without a compelling reason to do so. This name is case-sensitive. Names may not match other registered names in a case-insensitive manner unless the Designated Expert(s) states that there is a compelling reason to allow an exception in this particular case.

Change Controller: For Standards Track RFCs, state “IESG”. For others, give the name of the responsible party. Other details (e.g., postal address, email address, and home page URI) may also be included.

Specification Document(s):
Reference to the document(s) that specifies the parameter, preferably including URI(s) that can be used to retrieve copies of the document(s). An indication of the relevant sections may also be included but is not required.

6.2.2. 初始注册表内容(Initial Registry Contents)

根据本文件,IANA在本注册表中注册了第4.2节中定义的Code Challenge方法参数名称。
o 代码挑战方法参数名称:Plain
o 变更控制人: IESG
o 规范文件。RFC 7636的第4.2节(本文档)。

o 代码挑战方法参数名称。S256
o 变更控制方:IESG
o 规范文件。RFC 7636的第4.2节(本文)。


Per this document, IANA has registered the Code Challenge Method Parameter Names defined in Section 4.2 in this registry. o Code Challenge Method Parameter Name: plain o Change Controller: IESG o Specification Document(s): Section 4.2 of RFC 7636 (this document)

o Code Challenge Method Parameter Name: S256 o Change Controller: IESG o Specification Document(s): Section 4.2 of RFC 7636 (this document)

7 安全注意事项(Security Considerations)

7.1. code_verifier的熵(Entropy of the code_verifier)

安全模型依赖于这样一个事实,即代码验证者不会被攻击者了解或猜测。坚持这一原则至关重要。 因此,代码验证器必须以这样的方式创建,即它在密码学上是随机的,具有高熵,攻击者不可能猜到它。

客户端应该创建一个至少有256位熵的“ code_verifier”。 这可以通过让合适的随机数生成器创建一个32字节的序列来完成。然后可以对八位位组序列进行base64url编码,以生成43个八位位组的URL安全字符串,以用作具有所需熵的“ code_challenge”。


The security model relies on the fact that the code verifier is not learned or guessed by the attacker. It is vitally important to adhere to this principle. As such, the code verifier has to be created in such a manner that it is cryptographically random and has high entropy that it is not practical for the attacker to guess.

The client SHOULD create a “code_verifier” with a minimum of 256 bits of entropy. This can be done by having a suitable random number generator create a 32-octet sequence. The octet sequence can then be base64url-encoded to produce a 43-octet URL safe string to use as a “code_challenge” that has the required entropy.

7.2 防止窃听者(Protection against Eavesdroppers)

在尝试“S256”方法后,客户端绝对不能降级为“plain”。支持PKCE的服务器必须支持“S256”,不支持PKCE的服务器将简单地忽略未知的“code_verifier”。因此,当“S256”出现时出现的错误只能意味着服务器故障或MITM攻击者正在尝试降级攻击。

S256”方法防止窃听者观察或拦截“code_challenge”,因为没有验证器就不能使用challenge。使用“plain”方法,攻击者有可能在设备上或http请求中观察到“code_challenge”。由于code challenge与本例中的code verifier相同,因此“plain”方法不能防止对初始请求的窃听。

使用“ S256”可以防止将“ code_verifier”值泄露给攻击者。

因此,不应该使用“plain”,它的存在只是为了与已部署的、请求路径已经受到保护的实现兼容。在新的实现中不应该使用“plain”方法,除非它们由于某些技术原因不能支持“S256”。

应该使用“ S256”code challenge 方法或其他密码安全code challenge 方法扩展。 “plain”的code challenge方法依赖于操作系统和传输安全性,不会将请求披露给攻击者。

如果code challenge 方法是“plain”并且要在授权“code”中返回该code challenge以实现无状态服务器,则必须以仅服务器可以解密和提取它的方式对其进行加密。


Clients MUST NOT downgrade to “plain” after trying the “S256” method.Servers that support PKCE are required to support “S256”, and servers that do not support PKCE will simply ignore the unknown “code_verifier”. Because of this, an error when “S256” is presented can only mean that the server is faulty or that a MITM attacker is trying a downgrade attack.

The “S256” method protects against eavesdroppers observing or intercepting the “code_challenge”, because the challenge cannot be used without the verifier. With the “plain” method, there is a chance that “code_challenge” will be observed by the attacker on the device or in the http request. Since the code challenge is the same as the code verifier in this case, the “plain” method does not protect against the eavesdropping of the initial request.

The use of “S256” protects against disclosure of the “code_verifier” value to an attacker.

The “S256” code challenge method or other cryptographically secure code challenge method extension SHOULD be used. The “plain” code challenge method relies on the operating system and transport security not to disclose the request to an attacker.

If the code challenge method is “plain” and the code challenge is to be returned inside authorization “code” to achieve a stateless server, it MUST be encrypted in such a manner that only the server can decrypt and extract it.

7.3 加盐code_challenge(Salting the code_challenge)

为了降低实现的复杂性,在code challenge的生成过程中没有加盐,因为code verifier包含足够的熵来防止暴力攻击。将一个公开已知的值连接到一个code verifier(包含256位熵),然后使用SHA256对其进行散列以产生一个code challenge,不会增加对code verifier进行暴力攻击的有效数值所需的尝试次数。

尽管“ S256”转换就像对密码进行哈希处理一样,但有一些重要的区别。 密码往往是熵值相对较低的单词,可以离线对其进行哈希处理,然后在字典中查找哈希值。 通过在哈希之前将唯一但公共的值连接到每个密码,可以极大地扩展攻击者需要搜索的词典空间。

现代图形处理器现在允许攻击者实时计算散列值,其速度比从磁盘上查找要快。这消除了为低熵密码增加蛮力攻击的复杂性的价值。


To reduce implementation complexity, salting is not used in the production of the code challenge, as the code verifier contains sufficient entropy to prevent brute-force attacks. Concatenating a publicly known value to a code verifier (containing 256 bits of entropy) and then hashing it with SHA256 to produce a code challenge would not increase the number of attempts necessary to brute force a valid value for code verifier.

While the “S256” transformation is like hashing a password, there are important differences. Passwords tend to be relatively low-entropy words that can be hashed offline and the hash looked up in a dictionary. By concatenating a unique though public value to each password prior to hashing, the dictionary space that an attacker needs to search is greatly expanded.

Modern graphics processors now allow attackers to calculate hashes in real time faster than they could be looked up from a disk. This eliminates the value of the salt in increasing the complexity of a brute-force attack for even low-entropy passwords.

7.4 OAuth的安全注意事项(OAuth Security Considerations)

[RFC6819]中介绍的所有OAuth安全性分析均适用,因此读者应仔细遵循它。


All the OAuth security analysis presented in [RFC6819] applies, so readers SHOULD carefully follow it.

7.5 TLS安全注意事项(TLS Security Considerations)

当前的安全注意事项可以在“安全使用传输层安全性(TLS)和数据报传输层安全性(DTLS)的建议” [BCP195]中找到。 这取代了OAuth 2.0 [RFC6749]中的TLS版本建议。


Current security considerations can be found in “Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)” [BCP195]. This supersedes the TLS version recommendations in OAuth 2.0 [RFC6749].

8. 补充

适用场景
没有服务端的纯桌面应用程序、安卓、IOS、浏览器插件程序等的原生客户端。
原生客户端软件一般是指没有后端服务器,所有代码都在用户本地设备上运行的软件(如Windows/Mac客户端或者iOS/Android客户端),因此想让原生客户端软件安全存放密钥(client secret)是不现实的,很容易被破解。

【1】使用pkce的单页应用程序的现代oauth
【2】为客户端而生的OAuth2.0协议之PKCE授权码模式
【3】Microsoft identity platform and OAuth 2.0 authorization code flow(微软平台和身份OAuth 2.0授权代码流)
【4】 OAuth 2.0 for Native Apps(原生应用的OAuth 2.0)(RFC8252)
【5】code_verifier在线生成