Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

51.2.15 - OAuth - ask to be transaction-specific #2092

Closed
elarlang opened this issue Sep 18, 2024 · 30 comments
Closed

51.2.15 - OAuth - ask to be transaction-specific #2092

elarlang opened this issue Sep 18, 2024 · 30 comments
Labels
1) Discussion ongoing Issue is opened and assigned but no clear proposal yet 6) PR awaiting review V51 Group issues related to OAuth _5.0 - prep This needs to be addressed to prepare 5.0

Comments

@elarlang
Copy link
Collaborator

elarlang commented Sep 18, 2024

Update: skip the long issue and jump to #2092 (comment)


Update: the requirement is moved to 51.2.15

Current requirement 51.2.2 51.2.15:

# Description L1 L2 L3
51.2.15 [ADDED] Verify that the replay of authorization codes into the authorization response is prevented either by using the PKCE flow or alternatively the OpenID Connect "nonce" parameter and the respective Claim in the ID Token. The PKCE challenge or OpenID Connect "nonce" must be transaction-specific and securely bound to the client and the user agent in which the transaction was started.

I'm quite confused, what is to goal for the requirement.

It starts with a claim to prevent authorization code replay into the authorization response - authorization code in authorization response is handled by the client and this is basically CSRF vector to prevent, it is covered now in 51.3.5:

# Description L1 L2 L3
51.3.5 [ADDED] Verify that, if the code flow is used, the OAuth Client has protection against CSRF attacks which trigger token requests, either by using PKCE functionality or checking the state parameter that was sent in the authorization request.

Further, it requires validating the nonce in ID token, but this is to mitigate ID token replay attack to (OIDC) the client, but for that we have also a separate requirement (at the moment it is in wrong section, but this is another topic to discuss):

# Description L1 L2 L3
51.3.2 [ADDED] Verify that the Client is using the PKCE flow or alternatively the OpenID Connect "nonce" parameter and the respective Claim in the ID Token.

For me the requirement 51.2.15 seems to mix different things. Or did I miss the actual point for the requirement?

@elarlang elarlang added 2) Awaiting response Awaiting a response from the original poster 1) Discussion ongoing Issue is opened and assigned but no clear proposal yet _5.0 - prep This needs to be addressed to prepare 5.0 V51 Group issues related to OAuth labels Sep 18, 2024
@csfreak92
Copy link
Collaborator

In the way I understood it, 51.2.2 is for ensuring that when you use PKCE challenge or OIDC nonce they should be transaction-specific to prevent replay of these codes as well.

No, 51.3.5 does not re-use those authorization codes as a CSRF protection. I haven't seen those authorization codes being used to prevent the CSRF vector. Maybe someone else has more knowledge about it from the community who can help us about this, but as far as I know that is not what those authorization codes help prevent.

Although, I believe you are correct that the way 51.3.2 is written it is already handled in 51.2.2. We can remove 51.3.2 then since 51.2.2 handles it.

@elarlang
Copy link
Collaborator Author

Ack, the focus is "transaction-specific".

Additionally, @randomstuff asked a question in #2041 (comment)

Is there any need to say the the nonce must be a unpredictable?

I think we need to reword it what problem the requirement solves and avoid duplication with other requirements.

@elarlang elarlang removed the 2) Awaiting response Awaiting a response from the original poster label Sep 22, 2024
@elarlang
Copy link
Collaborator Author

@randomstuff @TobiasAhnoff - any ideas how to solve this?

@randomstuff
Copy link
Contributor

Although, I believe you are correct that the way 51.3.2 is written it is already handled in 51.2.2. We can remove 51.3.2 then since 51.2.2 handles it.

Yes, I agree. They are redundant.

@randomstuff
Copy link
Contributor

Is there any need to say the the nonce must be a unpredictable?

I think, this should probably be somewhere and I don't believe it's currently really states but it is really more general than OAuth and should probably be somewhere else as well.

This is related to:

6.3.1, Verify that all random numbers, random file names, and random strings are generated using a cryptographically-secure pseudo-random number generator (CSPRNG) when these random values are intended to be not guessable by an attacker.

6.3.3, Verify that random numbers are created with proper entropy even when the application is under heavy load, or that the application degrades gracefully in such circumstances.

"sufficient entropy" is somewhat left to interpretation. OAuth requires at least 128 bits and recommends 160 bits of entropy for tokens:

The probability of an attacker guessing generated tokens (and other credentials not intended for handling by end users) MUST be less than or equal to 2^(-128) and SHOULD be less than or equal to 2^(-160).

Note that the the wording in the the OAuth 2.1 draft is more general than the requirement in 6.3.3 as it applies to random/opaque tokens and for signature/MAC tokens.

So the questions are:

  • Is there any need for an explicit mention of this in the OAuth chapter?
  • Or it it enough to have it stated in the Crytpography chapter?
  • Is the current requirements in the cryptography chapter enough?

@elarlang
Copy link
Collaborator Author

I think the randomness is well covered in V6 (and if it is not, for general requirements it should be covered there)

Ack, the focus is "transaction-specific".

I think the main focus should be "transaction-specific" to mitigate replay attacks.

@TobiasAhnoff
Copy link

A thing to note is that this is part of the "OAuth Authorization Server", not the "OIDC OpenID Provider" section, so OIDC details should be avoided in the requirement, split, moved to OIDC or should we mix OAuth and OIDC in this case?

For OAuth we could have

Verify that the replay of authorization codes into the authorization response is prevented by using PKCE with a transaction-specific challenge which is securely bound to the client and the user agent in which the transaction was started.

For OIDC,, given that it is clear that all OAuth requirements also applies to OIDC it could be:

Verify that the replay of authorization codes into the authorization response is prevented either by using OAuth PKCE or alternatively the OpenID Connect "nonce" parameter and the respective Claim in the ID Token. The OpenID Connect "nonce" must be transaction-specific in the same way as the PKCE challenge.

or if we mix, like suggested above

Verify that the replay of authorization codes into the authorization response is prevented either by using the PKCE flow or alternatively the OpenID Connect "nonce" parameter and the respective Claim in the ID Token. The PKCE challenge or OpenID Connect "nonce" must be transaction-specific and securely bound to the client and the user agent in which the transaction was started.

I think none of them is perfect, but I think it is good to keep OIDC details separate to make it clear that OAuth can be used without OIDC and ID Tokens.

@elarlang
Copy link
Collaborator Author

I think my initial comment applies to the last proposal as well. I would not like to mix and duplicate ID token replay (51.3.2 (it is in incorrect section)) and OAuth client CSRF (51.3.5), additionally general PKCE requirement.

Probably 2 directions from here:

  • mention transaction-specific in each related requirement separately
  • write one requirement to declare a "transaction-specific" problem.

In a way, if we have requirements like "Verify that, if the code flow is used, the OAuth Client has protection against CSRF attacks", then if the cause of not having the defense is the missing transaction-specific token, it is still the same requirement and the same problem, it is just finding the technical detail in it.

@TobiasAhnoff
Copy link

They way I see it (based on https://github.com/OWASP/ASVS/pull/2122/files) this is addressed by

51.2.3
Verify that, if the code grant is used, the authorization server mitigates authorization code interception attacks by requiring PKCE. For authorization requests, the authorization server must require a valid code_challenge value and must not accept code_challenge_method 'plain'. For a token request, it must require validation of the "code_verifier" parameter.

And for OIDC

51.5.1
Verify that the Client (as the Relying Party) mitigates ID Token replay attacks. For example, by ensuring that the nonce claim in the ID Token matches the nonce value sent in the Authentication Request to the OpenID Provider (in OAuth2 refereed to as the Authorization request sent to the Authorization Server)

So 51.2.2, 51.3.5 and 51.3.2 can be removed since they are addressed/replaced by 51.2.3 and 51.5.1 (and randomness is well covered in V6), maybe add CSRF for 51.2.3?

Verify that, if the code grant is used, the authorization server mitigates authorization code interception and CSRF attacks by requiring PKCE. For authorization requests, the authorization server must require a valid code_challenge value and must not accept code_challenge_method 'plain'. For a token request, it must require validation of the "code_verifier" parameter.

Or have I confused latest numbering?

@elarlang
Copy link
Collaborator Author

elarlang commented Oct 7, 2024

We need to do de-duplication round later, I have not opened issues for those yet, as the first goal is to get all requirements in.

For this, the goal seems to be "transaction-specific", all other parts are too mixed here and are covered somewhere else.

@TobiasAhnoff
Copy link

Ok, then I think this issue needs to suggest one requirement for OAuth and one for OIDC, perhaps this could work?

OAuth

Verify that the replay of authorization codes into the authorization response is prevented by using PKCE with a transaction-specific challenge which is securely bound to the client and the user agent in which the transaction was started.

OIDC (given that it is clear that all OAuth requirements also applies to OIDC)

Verify that, if OAuth PKCE is not used, the replay of authorization codes into the authorization response is prevented by verifying the OpenID Connect "nonce" parameter and the respective Claim in the ID Token. The OpenID Connect "nonce" must be transaction-specific in the same way as the OAuth PKCE challenge.

@elarlang elarlang changed the title 51.2.2 - what is the purpose for the requirement? 51.2.15 - what is the purpose for the requirement? Oct 16, 2024
@elarlang
Copy link
Collaborator Author

As we have some renumbering and modifications, then I'll recheck everything and make an update.

The requirement is now moved to 51.2.15:

# Description L1 L2 L3
51.2.15 [ADDED] Verify that the replay of authorization codes into the authorization response is prevented either by using the PKCE flow or alternatively the OpenID Connect "nonce" parameter and the respective Claim in the ID Token. The PKCE challenge or OpenID Connect "nonce" must be transaction-specific and securely bound to the client and the user agent in which the transaction was started.

Verify that the replay of authorization codes into the authorization response is prevented either by using the PKCE flow ...

I tried to understand, from where the "replay codes into the authorization response" comes, because for me it does not make too much sense. Potential resource.

The "authorization code response" comes from the AS, but in reality, it is a request from AS to the client.

Authorization code replay can happen:

  • resend authorization code to the OAuth client, that can send it to the AS with the token request
  • doing directly token request to the AS

Against "replay" the actual defense is that the authorization code is "one time use", and it is covered by 51.2.1.

From the defined attack vector to mitigate "authroization code replay" point of view, the PKCE seems offtopic here. The PKCE is against authorization code interception/injection.

... or alternatively the OpenID Connect "nonce" parameter and the respective Claim in the ID Token.

This part is talking about ID token and the 'nonce' claim, that is defense against ID token replay attack and it is covered by 51.4.1.

From the authorization code replay attack point of view, it seems also offtopic.

The PKCE challenge or OpenID Connect "nonce" must be transaction-specific and securely bound to the client and the user agent in which the transaction was started.

This is most likely from here and is also meant against authorization code interception/injection attacks.

From the authorization code replay attack point of view, being transaction-specific provides defense against replay, but it then requires, that AS keeps the list of already used PKCE and nonce values (that is actually recommended to do for AS: Authorization servers are encouraged to make a reasonable effort at detecting and preventing the use of constant PKCE challenge or OpenID Connect nonce values.).

"transaction-specific" part is not covered as a separate requirement.

So, TLDR - the requirement was actually against authorization code interception/injection attacks.


The proposal

Verify that the client validates the values (such as authorization code, ID token) sent to the client or received by the client to be the result of the authorization flow that was initiated by the same client. It requires, that client-generated secrets, such as PKCE 'code_challenge', 'state', or OIDC 'nonce', are not guessable, are transaction-specific, and securely bound to the client and the user agent in which the transaction was started.

@elarlang elarlang changed the title 51.2.15 - what is the purpose for the requirement? 51.2.15 - OAuth - ask to be transaction-specific Oct 17, 2024
@randomstuff
Copy link
Contributor

randomstuff commented Oct 17, 2024

Potential resource.

In complete objectivity, I have to recommend this resource. 😉 → I misinterpreted the meaning of the previous comment :)

@elarlang
Copy link
Collaborator Author

Potential resource.

Note that it was meant to be the source, from where the confusing wording is coming from.

@randomstuff
Copy link
Contributor

randomstuff commented Oct 17, 2024

The fact that the authorization code is single use indeed prevent against authorization code replay (implemented AS-side).

From the authorization code replay attack point of view, being transaction-specific provides defense against replay, but it then requires, that AS keeps the list of already used PKCE and nonce values (that is actually recommended to do for AS:

I think nonce provides a more limited form of client-side authorization code replay protection: it does not prevent the authorization code to be exchanged more than once but the client will not accept the resulting ID token twice.

In other words,

  • it prevents a malicious user from trying to replay the authorization code and successfully getting a session;
  • but it does not prevent a malicious client from exchanging the authorization code and obtaining a OIDC access token (granting access to PII which he would have had access to anyway).

I think a similar argument can be made about PKCE.

@randomstuff
Copy link
Contributor

randomstuff commented Oct 17, 2024

See for reference on this topic 4.5.3 from the Oauth Security topics draft.

And:

4.3.1 Authorization Code in Browser History

Countermeasures:

  • Authorization code replay prevention as described in [RFC6819], Section 4.4.1.1, and Section 4.5.

@elarlang
Copy link
Collaborator Author

I agree that I applied PKCE code_challenge + code_verifierone-time-use to nonce, that is not valid move. But this was all comments for the current requirement that I propose to delete and replace with a new requirement. So let's focus on this one:

Verify that the client validates the values (such as authorization code, ID token) sent to the client or received by the client to be the result of the authorization flow that was initiated by the same client. It requires, that client-generated secrets, such as PKCE 'code_challenge', 'state', or OIDC 'nonce', are not guessable, are transaction-specific, and securely bound to the client and the user agent in which the transaction was started.

@randomstuff
Copy link
Contributor

randomstuff commented Oct 17, 2024

The first sentence says:

that was initiated by the same client.

but then:

and securely bound to the client and the user agent in which the transaction was started

Shouldn't the first sentence be instead something like:

Verify that the client validates the values (such as authorization code, ID token) sent to the client or received by the client to be the result of the authorization flow that was initiated from the same user session.


It requires, that client-generated secrets, such as PKCE 'code_challenge', 'state', or OIDC 'nonce', are not guessable, [...]

I would use code_verifier instead of code_challenge here (?). I think the requirement is equally valid with either but I think it makes more sense this way (as code_challenge is just a deterministic function of code_verifier).


are transaction-specific
and securely bound to the client and the user agent in which the transaction was started.

I feel we miss the notion that they are bound to some sort of user session as well (i.e. that a transaction is bound to a given user session).

See for example OAuth 2.1 draft section 7.9:

The traditional countermeasure is that clients pass a random value, also known as a CSRF Token, in the state parameter that links the request to the redirect URI to the user agent session as described.

[...]

If state is used for carrying application state, and integrity of its contents is a concern, clients MUST protect state against tampering and swapping. This can be achieved by binding the contents of state to the browser session and/or signed/encrypted state values [I-D.bradley-oauth-jwt-encoded-state].

Or OAuth Security topics draft 4.5.3.2:

OpenID Connect's existing nonce parameter can protect against authorization code injection attacks. The nonce value is one-time use and created by the client. The client is supposed to bind it to the user agent session and sends it with the initial request to the OpenID Provider (OP).

@elarlang
Copy link
Collaborator Author

All valid points, do you want to propose full requirement as well?

@elarlang
Copy link
Collaborator Author

Just for one more direction how to set up the first part.

Verify that the client accepts the values (such as authorization code, access token, ID token) from the authorization server only if those are created as a result of the authorization flow that was initiated by the same user session.

The "user session" or "user agent session" need to be written the way that is valid for public clients and confidential clients.

Even here, only session is enough, it must be transaction specific - it means you can not use the same value many times for the same session.

My intent is to cover the transaction-specific part with the requirement, but the first part, which is used to explain the need for transaction-specific behavior, is a bit too wide and overlaps already with OAuth client CSRF protection (51.3.2) and OIDC client ID token replay protection (51.5.1).

@randomstuff
Copy link
Contributor

randomstuff commented Oct 18, 2024

With these modifications, that would be:

Verify that the client validates the values (such as authorization code, ID token) sent to the client or received by the client to be the result of the authorization flow that was initiated by the same user agent session and transaction. Client-generated secrets, such as PKCE 'code_verifier', 'state', or OIDC 'nonce', must not be guessable, must be transaction-specific, and must be securely bound to the client and the user agent session in which the transaction was started.

@jmanico
Copy link
Member

jmanico commented Oct 18, 2024

Small suggestion here:

Verify that the client validates the values (such as the authorization code or ID token) sent to or received by the client to ensure they result from the authorization flow was initiated by the same user agent session and transaction. This requires that client-generated secrets, such as the PKCE 'code_verifier,' 'state,' or OIDC 'nonce,' are not guessable, are specific to the transaction, and are securely bound to both the client and the user agent session in which the transaction was started.

@randomstuff
Copy link
Contributor

randomstuff commented Oct 18, 2024

@jmanico, yes this is much better! Two minor grammar fixes (I think):

Verify that the client validates the values (such as the authorization code or ID token) sent to or received by the client to ensure they result from an authorization flow which was initiated by the same user agent session and transaction. This requires that client-generated secrets, such as the PKCE 'code_verifier,' 'state,' or OIDC 'nonce,' are not guessable, are specific to the transaction, and are securely bound to both the client and the user agent session in which the transaction was started.

@elarlang
Copy link
Collaborator Author

I explain changes proposed here #2092 (comment)

  • "client validates" > "client accepts" - I think the initially proposed "validate" is not correct, because the point here is that the client can accept those values only, if it can be sure that those are coming from user's own initiated session and transaction
  • "sent to or received by the client" > "from the authorization server"

First change is important, other is more question of a point of view.

@randomstuff
Copy link
Contributor

OK that would give us:

Verify that the client accepts the values (such as the authorization code or ID token) from the authorization server to ensure they result from an authorization flow which was initiated by the same user agent session and transaction. This requires that client-generated secrets, such as the PKCE 'code_verifier' 'state' or OIDC 'nonce' are not guessable, are specific to the transaction, and are securely bound to both the client and the user agent session in which the transaction was started.


Small questions about the wording:

Verify that the client accepts the values (such as the authorization code or ID token) from the authorization server to ensure they result from an authorization flow which was initiated by the same user agent session and transaction.

Isn't "authorization flow" and "transaction" redundant here?

In which cases should we talk about "authorization flow" or about "transaction"?


Another thing which is not very clean is that the main requirement says:

result from an authorization flow which was initiated by the same user agent session and transaction

but in the next sentence, the scope of the requirement is expanded into what I think is another consideration:

are not guessable


Another thing which is somewhat weird is:

Verify that the client accepts the values (such as the authorization code or ID token) […]

The client cannot really verify the authorization code directly. It can check the state, use PKCE to help the server mitigate authorization code injection, check the scope (or authorization_details) after the authorization code exchange, check the ID token after the authorization code exchange, etc.


I'm wondering the current propositions are still somewhat weird or at least not very very precise even if they convey the general idea.

@elarlang
Copy link
Collaborator Author

Isn't "authorization flow" and "transaction" redundant here?

Please propose correction.

but in the next sentence, the scope of the requirement is expanded into what I think is another consideration:

Verify that the client accepts values only if (what must be done) > it can be achieved by using not guessable value (how it must be done). Personally I can not see a problem here.

The client cannot really verify the authorization code directly. It can check the state, use PKCE to help the server mitigate authorization code injection, check the scope (or authorization_details) after the authorization code exchange, check the ID token after the authorization code exchange, etc.

This was my reason to change "validate" to "accept" in #2092 (comment)

@randomstuff
Copy link
Contributor

What about something such as:

Verify that the client securely scopes a given interactive OAuth authorization flow to a user agent session and transaction. This requires that client generated such as 'state', PKCE 'code_verifier' and OIDC 'nonce' are not guessable, are specific to the transaction, and are securely bound to both the client and the user agent session in which the transaction was started. This requires as well that cross-session or cross-transaction injection of values generated by the authorization server (such as ID token, authorization code) is mitigated by the client.

@elarlang
Copy link
Collaborator Author

I prefer to develop our previous version.

@elarlang
Copy link
Collaborator Author

For me it seems that one important part ("accept" + "only if" got lost from #2092 (comment)). So updated proposal:

Verify that the client accepts the values (such as the authorization code or ID token) from the authorization server only if these result from an authorization flow that was initiated by the same user agent session and transaction. This requires that client-generated secrets, such as the PKCE 'code_verifier', 'state' or OIDC 'nonce' are not guessable, are specific to the transaction, and are securely bound to both the client and the user agent session in which the transaction was started.

As the 2nd part feels a bit duplication, there is potential for improvements, but if there are no mistakes or errors to point out, I'm ok to go in with that.

@elarlang
Copy link
Collaborator Author

The proposed requirement is valid for OAuth Client and OIDC Client... So the only valid move seems to be to add it into to V51.1 Generic OAuth and OIDC security.

@elarlang elarlang added the 5) awaiting PR A proposal hs been accepted and reviewed and we are now waiting for a PR label Oct 23, 2024
elarlang pushed a commit to elarlang/ASVS that referenced this issue Oct 23, 2024
@elarlang elarlang added 6) PR awaiting review and removed 5) awaiting PR A proposal hs been accepted and reviewed and we are now waiting for a PR labels Oct 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1) Discussion ongoing Issue is opened and assigned but no clear proposal yet 6) PR awaiting review V51 Group issues related to OAuth _5.0 - prep This needs to be addressed to prepare 5.0
Projects
None yet
Development

No branches or pull requests

5 participants