Martin Geisse
Martin Geisse

Reputation: 1461

In OAuth2 with PKCE, why must the challenge be encrypted in responses?

In https://www.rfc-editor.org/rfc/rfc7636#section-4.4 it is stated that the challenge can be associated with the authorization code by including it in the code, but only in encrypted form (alternatively store it on the server, which is not related to my question). Why must it be encrypted?

It seems obvious to me that the challenge should not be possible to alter, because then a later request for an access code could include a new challenge that was never presented to the server, and for which an attacker conveniently has a code verifier ready. However, to protect against modification, it would be sufficient to include a signature in the authorization code -- encrypting the challenge would not be necessary.

Section 4.4 also says that "The server MUST NOT include the "code_challenge" value in client requests in a form that other entities can extract". Suppose that either the requestor or a third party could extract the code challenge -- why is that harmful? The requestor already knows the code challenge, and a third-party attacker cannot derive the code verifier from it.

Upvotes: 1

Views: 748

Answers (3)

Advena
Advena

Reputation: 2243

The whole point of Proof Key for Code Exchange (PKCE) is to prevent request interception and reuse attacks. It achieves this by requiring a code verifier with every request between the client and the authorization server. These code verifier's are:

  • The authorization code (code), issued by the authorization server.
  • The code verifier (code_verifier), a high-entropy secret used to prove the client’s legitimacy.
  • The code challenge (code_challenge), which is derived from the code_verifier (usually SHA-256 + Base64) and sent in the initial request.

When the client first requests authorization, it sends the code_challenge and code_challenge_method to the authorization server. Since the code_challenge is just a hash of the code_verifier, it isn’t encrypted. Once the user is authenticated, the authorization server stores the code_challenge and returns an authorization code (code) to the client.

According to the RFC:

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.

How the Authorization Code (code) can be issued

There are two ways the authorization server can issue the code:

Stateful Approach (Secure)

One method is to generate a random code and store it in the database, along with the code_challenge, code_challenge_method, and the user’s ID. When the client later exchanges the code for a token, the server retrieves the stored data and verifies it. Since the code_challenge is never exposed outside the server, this approach is inherently secure.

Stateless Approach (Potential Security Risk)

Another approach is to derive the code itself using the user’s ID, code_challenge, and code_challenge_method, instead of storing them in a database. This allows the server to later extract the code_challenge and code_challenge_method from the code without any need of a Database.

However, this introduces a security risk: if the authorization code is intercepted, an attacker could also extract the code_challenge and code_challenge_method weakening the PKCE mechanism.

The Need for Encryption

To mitigate this risk, the RFC suggests encrypting the code in stateless implementations:

Typically, the "code_challenge" and "code_challenge_method" values are stored in encrypted form within the "code" itself (statless), but alternatively, they could be stored on the server (stateful). The server MUST NOT include the code_challenge in client requests in a form that other entities can extract.

In other words, if the code itself contains the code_challenge, it must be encrypted so that only the authorization server can extract it. Without encryption, an attacker who intercepts the code could potentially bypass the PKCE protections.

Upvotes: 0

robergd
robergd

Reputation: 1

The instructions in https://www.rfc-editor.org/rfc/rfc7636#section-4.4 apply to a generic code_challenge_method.

If the "plain" method is used, where code_challenge equals code_verifier, and the server does not protect (encrypt) the code_challenge, an attacker can obtain both the code_verifier and the authorization_code to forge a malicious access token request.

Upvotes: 0

Shanu Reddy
Shanu Reddy

Reputation: 35

Why must it be encrypted?

With PKCE implementation the authorization server does not have the client secret. It uses the code_challenge (an encrypted form of code_verifier). you can treat code_verifier as client_secret. Since client_secret cannot be sent through the front channel we are encrypting it. Once the authorization_code is generated see section 4.6 how the authorization server verifies it. Here authorization_code and code_challenge are sent through the back channel.

Upvotes: 0

Related Questions