OWASP / ASVS

Application Security Verification Standard
Creative Commons Attribution Share Alike 4.0 International
2.69k stars 653 forks source link

Proposal/discussion: OIDC requirement about ID token only being used to prove that the user has been authenticated (edit: a general requirement for allowing only intended usage for tokens) #2005

Open deleterepo opened 1 month ago

deleterepo commented 1 month ago

Developers sometimes mix up ID tokens and access tokens, especially in first-party scenarios, such as the case where both the client and the resource server, such as an API, is under their control. Using the ID token to make authorization decisions is a security issue, as there is no mechanism that ties the ID token to the API. Thus if an attacker steals the ID token in this case, they can use it to act as a legitimate client and call the API. For access tokens, these can be "sender constrained", such that the access token is bound to a specific sender. If an access token is stolen, an attacker can't necessarily use it to access the API since the token can be bound to the original client that requested it.   From https://oauth.net/2/access-tokens/:

Access tokens may be either "bearer tokens" or "sender-constrained" tokens. Sender-constrained tokens require the OAuth client to prove possession of a private key in some way in order to use the access token, such that the access token by itself would not be usable.

Another way of looking at this is the audience claim for each token. For the ID token, the intended recipient is the client, whereas for the access token, it's the RS.   That's a lot to digest 🤢, but the requirement itself can be as simple as this: Verify that the ID token is only used to prove that the user has been authenticated, and is not accepted as an authorization token by the Resource Server.

randomstuff commented 1 month ago

Verify that the ID token is only used to prove that the user has been authenticated, and is not accepted as an authorization token by the Resource Server.

And the other way around? Verify that access tokens are not recognized as ID token?

In addition, would any requirement against ID token / access token cross-JWT confusion make sense? (such as making sure that "aud" values are different for ID tokens and for access tokens?)

elarlang commented 1 month ago

Based on my understanding the typ must be checked for that and I have addressed the topic in the issue: https://github.com/OWASP/ASVS/issues/1967

ping @deleterepo @randomstuff - do you think/agree that checking the typ solves the issue or we need some additional requirement for that?

randomstuff commented 1 month ago

do you think/agree that checking the typ solves the issue or we need some additional requirement for that?

AFAIU, this is not really enough (not as simple as that) in general because OpenID ID token does not mandate any typ. As far as I understand, the type might be missing but a type might be present. It might be JWT (which is very general) or could be something else (?).

In addition, while RFC 9068 requires using application/at+jwt for JWT access tokens, it nos always used in practice.

For example, Keycloak currently uses 'typ': 'JWT' for both access tokens and ID tokens.

elarlang commented 1 month ago

The wording needs (a lot of) work, but maybe this as a direction: Verify that the token is made for that type of usage before accepting it, such as an ID token for authentication and an access token for authorization without allowing cross-usage.

jmanico commented 4 weeks ago

How about: (this is a bit too verbose but a step in the right direction I think)

Verify that tokens are used according to their intended purpose: ID tokens should be used exclusively to prove authentication, while access tokens should be used strictly for delegation or authorization. Ensure that cross-usage between ID tokens and access tokens is explicitly disallowed.

randomstuff commented 4 weeks ago

This is not very directly actionnable but is it not very easy to make this more actionnable.

What about:

Verify that ID tokens issued or consumed by the system cannot be used as JWT access tokens. The can for example be achieved by using different values for the iss claims (eg. opaque client_id for ID tokens and server URI for the access tokens).

Verify that JWT access tokens issued or consumed by the system cannot be used as ID tokens. This can for example be achieved by using different values for the iss claims (eg. opaque client_id for ID tokens and server URI for the access tokens).

Or more detailed formulation:

When consuming an ID tokens, verify that JWT access tokens cannot be used instead. This can be achieved by requiring the usage of a nonce.

When consuming a JWT access tokens, verify ID token cannot be used instead. This can be achieved by requiring the presence of a suitable scope claim value.

When producing an ID token, verify that it cannot be interpreted as a JWT access token by the consuming application (HOW?)

When producing a JWT access token, verify that it cannot be interpreted as an ID token by the consuming application (HOW?)

None of these formulations cover the other cases of JWT token mixup.

elarlang commented 3 weeks ago

I think this direction goes to the cheat sheet side, we are not limited to id-token and access token, but can add refresh token into the mix.

Also a bit the point of view - "Verify that ID-token can not be used as access token" vs "Verify that only valid ID-token can be used as ID-token".

elarlang commented 2 days ago

This discussion here covers also #2049 and I closed this one to find the solution here.

Probably best requirement proposal was in https://github.com/OWASP/ASVS/issues/2049#issuecomment-2336813309

Verify that only access tokens can be used for authorization, not other kinds of tokens like ID Tokens or Logout tokens.

elarlang commented 2 days ago

My attempt for catch all requirement:

Verify that tokens (such as ID tokens, access tokens and refresh tokens) can only be used according to their intended purpose without allowing cross-usage between them.

ping @randomstuff @TobiasAhnoff - any (dis)agreements or feedback?

TobiasAhnoff commented 1 day ago

Verify that tokens (such as ID tokens, access tokens and refresh tokens) can only be used according to their intended purpose without allowing cross-usage between them.

I agree, but perhaps it would be good with one example (like @jmanico suggested) to make it clearer, even if it does not list all scenarios and technical details, it highlights (in my experience) the most common token-confusion, like this

Verify that tokens (such as ID tokens, access tokens and refresh tokens) can only be used according to their intended purpose without allowing cross-usage between them. In example ID tokens should be used exclusively to prove user authentication for the client.

elarlang commented 1 day ago

We can list examples if needed.

General feedback - the context for ASVS requirement is "strong true of false requirement" (must), but not recommendation (should). So the language must be more strict, instead of "should be" we can use "can only be" or "must be" (see also https://datatracker.ietf.org/doc/html/rfc2119).

elarlang commented 1 day ago

For the section, the requirement is valid for OAuth and OIDC and may be more general token validation, although it mentions OAuth-specific tokens as examples.

elarlang commented 1 day ago

To make it more clear and "actionable". My proposal is to add the proposed requirement as a general token requirement to to V3.5:

Verify that tokens (such as ID tokens, access tokens and refresh tokens) can only be used according to their intended purpose without allowing cross-usage between them. In example ID tokens cam only be used to prove user authentication for the client.

ping @TobiasAhnoff @deleterepo @tghosth @randomstuff

tghosth commented 21 hours ago

@elarlang

Verify that tokens (such as ID tokens, access tokens and refresh tokens) can only be used for their intended purpose. For example, ID tokens can only be used to prove user authentication for the client.

That would be my suggestion. I think this sounds like L3 to me. I would also tag @ryarmst as he is looking at V3.

elarlang commented 21 hours ago

This is for sure L1. It's pretty much the same as checking that the token is in a valid time window (not expired).

V3 as a category here is questionable, as these kinds of token-questions are not really session management questions.