Subject: [OAUTH-WG] OAuth Security BCP -15

From: Aaron Parecki <[email-masked]>
Date: Sun, 5 Apr 2020 11:42:49 -0700

Section 2.1.1 says:

   Clients MUST prevent injection (replay) of authorization codes into
>    the authorization response by attackers.  The use of PKCE [RFC7636]
>    is RECOMMENDED to this end.  The OpenID Connect "nonce" parameter and
>    ID Token Claim [OpenID] MAY be used as well.

Minor nit: this should be "ID Token claim" with a lowercase "c". I spent a
while trying to figure out what an "ID Token Claim" is before realizing
this sentence was referring to the "nonce" claim in an ID Token.

Aside from that, I'm struggling to understand what this section is actually
saying to do. Since this is in the "Authorization Code Grant" section, is
this saying that using response_type=code is fine as long as the client
checks the "nonce" in the ID Token obtained after it uses the authorization
code? It seems like that would still allow an authorization code to be
injected. I don't see how the "nonce" parameter solves anything to do with
the authorization code, it seems like it only solves ID token injections
via response_type=id_token.

In any case, this section could benefit from some more explicit
instructions on how exactly to prevent authorization code injection attacks.

----
Aaron Parecki
aaronparecki.com
@aaronpk <http://twitter.com/aaronpk>

---

From: David Waite <[email-masked]>
Date: Sun, 5 Apr 2020 16:12:54 -0600

On Apr 5, 2020, at 12:42 PM, Aaron Parecki <[email-masked]> wrote:
> Aside from that, I'm struggling to understand what this section is actually saying to do. Since this is in the "Authorization Code Grant" section, is this saying that using response_type=code is fine as long as the client checks the "nonce" in the ID Token obtained after it uses the authorization code? It seems like that would still allow an authorization code to be injected. I don't see how the "nonce" parameter solves anything to do with the authorization code, it seems like it only solves ID token injections via response_type=id_token.

With PKCE, the client sends a challenge value to the authorization endpoint and a verifier value to the token endpoint. The authorization server will thus be able to correlate the request and response were made by the same client instance, and reject issuing tokens if there is an issue.

With OIDC nonce, the client sends a nonce value to the auth endpoint and _receives_ that nonce back inside the id_token. The client can verify that the response corresponds to the request it made and reject requesting/using tokens if there is an issue.

The first solution will almost inarguably lead to better implementations, as the single AS is taking responsibility for verification before issuing tokens, vs relying on potentially many client instances to do proper verification. But both do solve the problem.

The problem I have with this choice is that a client library will not necessarily know PKCE is being honored vs ignored by the AS. So a client would need to always do _both_ to be a good citizen in some cases. So I would prefer that clients and servers MUST support PKCE, but servers MAY also allow nonce usage for security in the case of non-compliant clients (with appropriately vetted conformance to OIDC).

> In any case, this section could benefit from some more explicit instructions on how exactly to prevent authorization code injection attacks.

Indeed.

-DW

---

From: Daniel Fett <[email-masked]>
Date: Mon, 6 Apr 2020 09:09:23 +0200

Hi Aaron,

Thanks for your feedback!

Am 05.04.20 um 20:42 schrieb Aaron Parecki:
> Minor nit: this should be "ID Token claim" with a lowercase "c". I
> spent a while trying to figure out what an "ID Token Claim" is before
> realizing this sentence was referring to the "nonce" claim in an ID Token.

Upper case "Claim" follows the convention in OIDC Core, which says for
example, "these additional requirements for the following ID Token
Claims apply".

To keep the documents consistent, I will change the sentence above to

"The OpenID Connect "nonce" parameter and the respective Claim in the ID
Token [OpenID] MAY be used as well."

>
> Aside from that, I'm struggling to understand what this section is
> actually saying to do. Since this is in the "Authorization Code Grant"
> section, is this saying that using response_type=code is fine as long
> as the client checks the "nonce" in the ID Token obtained after it
> uses the authorization code? It seems like that would still allow an
> authorization code to be injected. I don't see how the "nonce"
> parameter solves anything to do with the authorization code, it seems
> like it only solves ID token injections via response_type=id_token.

The injected authorization code would always refer to a different
session (started with a different nonce). The client would therefore get
an ID Token with a different nonce. The assumption is that the client
would then throw away both the ID Token and the access token.

Does that make sense?

> instructions on how exactly to prevent authorization code injection

Indeed, we should add a sentence or two on that.

-Daniel

---

From: Aaron Parecki <[email-masked]>
Date: Mon, 6 Apr 2020 07:09:10 -0700

>
> The injected authorization code would always refer to a different session
> (started with a different nonce). The client would therefore get an ID
> Token with a different nonce. The assumption is that the client would then
> throw away both the ID Token and the access token.

This is true as long as the client actually validates the ID token it
obtained at the token endpoint, even though it may have already obtained
one from the authorization response. (e.g. response_type=code+id_token). It
feels like this should be explained in a little more detail, since having
to validate two ID tokens to protect against this attack is not necessarily
obvious.

Aaron

----
Aaron Parecki
aaronparecki.com

On Mon, Apr 6, 2020 at 12:09 AM Daniel Fett <[email-masked]> wrote:

> example, "these additional requirements for the following ID Token Claims
> apply".
>
> section, is this saying that using response_type=code is fine as long as
> the client checks the "nonce" in the ID Token obtained after it uses the
> authorization code? It seems like that would still allow an authorization
> code to be injected. I don't see how the "nonce" parameter solves anything
> to do with the authorization code, it seems like it only solves ID token
> injections via response_type=id_token.
>
> The injected authorization code would always refer to a different session
> (started with a different nonce). The client would therefore get an ID
> Token with a different nonce. The assumption is that the client would then
> throw away both the ID Token and the access token.
>
> Does that make sense?
>
>

---

From: Daniel Fett <[email-masked]>
Date: Mon, 6 Apr 2020 22:06:52 +0200

Am 06.04.20 um 16:09 schrieb Aaron Parecki:
>     session (started with a different nonce). The client would
>     therefore get an ID Token with a different nonce. The assumption
>     is that the client would then throw away both the ID Token and the
>     access token.
>
>
> obtained at the token endpoint, even though it may have already
> obtained one from the authorization response. (e.g.
> response_type=code+id_token). It feels like this should be explained
> in a little more detail, since having to validate two ID tokens to
> protect against this attack is not necessarily obvious.

Thanks, that is an important point. I will propose some text on that.

-Daniel