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

OIDC login final redirect to callback URL fails with missing nonce #36871

Open
jmullo opened this issue Oct 28, 2024 · 10 comments
Open

OIDC login final redirect to callback URL fails with missing nonce #36871

jmullo opened this issue Oct 28, 2024 · 10 comments

Comments

@jmullo
Copy link

jmullo commented Oct 28, 2024

Title: OIDC login final redirect to callback URI fails with missing nonce

Description:
Error: "state query param does not contain url or nonce"

URL in browser: https://our.site.com/cb?code=uuid-code&state=url%3Dhttps%3A%2F%2Four.site.com%2F

Repro steps:
OIDC login flow with Cognito as identity provider.

@jmullo jmullo added bug triage Issue requires triage labels Oct 28, 2024
@jmullo
Copy link
Author

jmullo commented Oct 29, 2024

Apparently there are two different ways Cognito can mess up here. It either drops the nonce from state and loses it completely. Or it drops the nonce from state and puts the nonce to callback URL as a separate query parameter.

For these kind of scenarios an option to disable the whole nonce validation in Envoy would be needed.

It's possible that Cognito doesn't like state being URL-encoded, and could work as base64-encoded(?)

@nezdolik
Copy link
Member

@jmullo which envoy features do you use for this flow?

@jmullo
Copy link
Author

jmullo commented Oct 30, 2024

@jmullo which envoy features do you use for this flow?

OIDC Authentication security policy for HTTPRoutes. Also JWT Authentication policy.

@steeni
Copy link

steeni commented Oct 31, 2024

Root issue here is that cognito login page doesn't handle state value properly and the nonce doesn't stay in the state but gets raised directly to the url parameter and when coming back to callback nonce has disappeared from the state. In their documentation they do not support urlencoded json state values (and I guess this extends to any format, json just so common that it was mentioned). If we would ask them to fix it they probably just refer that section of their documentation. https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html#get-authorize-request-parameters

Implementing the point 3 here #36276 would probably help because then nonce would not be part of the state. Alternatively if the state value would be base64 urlencoded (base64 but with / and + changed to _ and - and no padding =) there would be less chance that it could break. Doing both would probably give most flexibility to handle with different oidc gateways. In the meantime I would recommend adding an option to disable nonce checking.

@nezdolik nezdolik added area/jwt_authn area/oauth and removed triage Issue requires triage labels Nov 1, 2024
@nezdolik
Copy link
Member

nezdolik commented Nov 1, 2024

@zhaohuabing
Copy link
Member

Apparently there are two different ways Cognito can mess up here. It either drops the nonce from state and loses it completely. Or it drops the nonce from state and puts the nonce to callback URL as a separate query parameter.

For these kind of scenarios an option to disable the whole nonce validation in Envoy would be needed.

It's possible that Cognito doesn't like state being URL-encoded, and could work as base64-encoded(?)

nonce is supposed to be transparent to the OIDC provider, I didn't realize that some OIDC providers would inspect the state parameter and remove the nonce outside of it.

@zhaohuabing
Copy link
Member

Implementing the point 3 here #36276 would probably help because then nonce would not be part of the state.

I'm not sure if this the right way to go. Nonce is an optional paramete in the standard. The oauth2 filter will need to know whether the provider supports the nonce parameter or not and supports both the nonce in the state and the standalone nonce, which complicate the implementation.

@steeni
Copy link

steeni commented Nov 8, 2024

Implementing the point 3 here #36276 would probably help because then nonce would not be part of the state.

I'm not sure if this the right way to go. Nonce is an optional paramete in the standard. The oauth2 filter will need to know whether the provider supports the nonce parameter or not and supports both the nonce in the state and the standalone nonce, which complicate the implementation.

Yeah, I understand. I notice that there is already an implementation of base64url encode/decode here https://github.com/envoyproxy/envoy/blob/main/source/common/common/base64.cc#L245 Maybe it could be used instead of percent-encoding in filter.cc. In theory, that should fix the immediate issue.

@zhaohuabing

This comment was marked as off-topic.

@zhaohuabing
Copy link
Member

zhaohuabing commented Dec 4, 2024

Implementing the point 3 here #36276 would probably help because then nonce would not be part of the state.

Report back here:

the nonce in the state paramter and the nonce parameter are two differenent things: the nonce in the state parameter is used for csrf prevention and is applicable for both oauth2 and oidc. Please note that the OIDC spec defines a seperate nonce parameter ,which is specifically designed to prevent replay attacks and is unique to OIDC. More discussion about state and nonce parameters can be found in this comment: #37050 (comment)

I've gone ahead to raise #37473 in envoy to use base64url encoding to fix this issue.

wbpcode added a commit that referenced this issue Dec 11, 2024
Commit Message: 
* Changes the state pramater to a json object to store the user state
before redirecting the user request to the auth server. Currently, the
json object has two fields: the original url and a nonce for csrf
prevention.
* Changes the state econding to
[Base64URL](https://datatracker.ietf.org/doc/html/rfc4648#section-5) to
fix [ AWS cognito doesn't support url encoded state
value](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html#get-authorize-request-parameters)
* Change the nonce from a plain timestamp to a random number to enhance
its security robustness. This addresses the "1. Generation" in this
issue #36276
* Small refacor: rename variables related to token_secret to hmac_secret
to improve clarity and consistency.

Example:
original state:
`{"url":"https://localhost:8080/login","nonce":"IPOom6PfIoFS+MmiV04aTJai8vUYlzyO5zUgT2G8mZA="}`
base64url encoded state:
`eyJ1cmwiOiJodHRwczovL2xvY2FsaG9zdDo4MDgwL2xvZ2luIiwibm9uY2UiOiJJUE9vbTZQZklvRlMrTW1pVjA0YVRKYWk4dlVZbHp5TzV6VWdUMkc4bVpBPSJ9`

Additional Description: The nonce in the [state parameter
](https://datatracker.ietf.org/doc/html/rfc6749#section-10.12)is used
for csrf prevention and is applicable for both oauth2 and oidc. Please
note that the OIDC spec defines a seperate [nonce
parameter](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest)
,which is specifically designed to prevent replay attacks and is unique
to OIDC.

More discussion about state and nonce parameters and be found in this
comment:
#37050 (comment)

Risk Level:
Testing: Unit test and integration test
Docs Changes:
Release Notes: Yes
Platform Specific Features:
[Optional Runtime guard:] A runtime gurad
"envoy.reloadable_features.oauth2_enable_state_nonce" has been added for
the new nonce in the state parameter.
[Optional Fixes #37049 #36871]
[Optional Fixes commit #PR or SHA]
[Optional Deprecated:]
[Optional [API
Considerations](https://github.com/envoyproxy/envoy/blob/main/api/review_checklist.md):]

Related Envoy Gateway issue:
envoyproxy/gateway#4625

I've tested this PR against AWS cognito using Envoy Gateway
SecurityPolicy, and it worked.

cc @missBerg @arkodg

---------

Signed-off-by: Huabing Zhao <[email protected]>
Signed-off-by: code <[email protected]>
Co-authored-by: code <[email protected]>
Co-authored-by: phlax <[email protected]>
zhaohuabing added a commit to zhaohuabing/envoy that referenced this issue Dec 13, 2024
Commit Message:
* Changes the state pramater to a json object to store the user state
before redirecting the user request to the auth server. Currently, the
json object has two fields: the original url and a nonce for csrf
prevention.
* Changes the state econding to
[Base64URL](https://datatracker.ietf.org/doc/html/rfc4648#section-5) to
fix [ AWS cognito doesn't support url encoded state
value](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html#get-authorize-request-parameters)
* Change the nonce from a plain timestamp to a random number to enhance
its security robustness. This addresses the "1. Generation" in this
issue envoyproxy#36276
* Small refacor: rename variables related to token_secret to hmac_secret
to improve clarity and consistency.

Example:
original state:
`{"url":"https://localhost:8080/login","nonce":"IPOom6PfIoFS+MmiV04aTJai8vUYlzyO5zUgT2G8mZA="}`
base64url encoded state:
`eyJ1cmwiOiJodHRwczovL2xvY2FsaG9zdDo4MDgwL2xvZ2luIiwibm9uY2UiOiJJUE9vbTZQZklvRlMrTW1pVjA0YVRKYWk4dlVZbHp5TzV6VWdUMkc4bVpBPSJ9`

Additional Description: The nonce in the [state parameter
](https://datatracker.ietf.org/doc/html/rfc6749#section-10.12)is used
for csrf prevention and is applicable for both oauth2 and oidc. Please
note that the OIDC spec defines a seperate [nonce
parameter](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest)
,which is specifically designed to prevent replay attacks and is unique
to OIDC.

More discussion about state and nonce parameters and be found in this
comment:
envoyproxy#37050 (comment)

Risk Level:
Testing: Unit test and integration test
Docs Changes:
Release Notes: Yes
Platform Specific Features:
[Optional Runtime guard:] A runtime gurad
"envoy.reloadable_features.oauth2_enable_state_nonce" has been added for
the new nonce in the state parameter.
[Optional Fixes envoyproxy#37049 envoyproxy#36871]
[Optional Fixes commit #PR or SHA]
[Optional Deprecated:]
[Optional [API
Considerations](https://github.com/envoyproxy/envoy/blob/main/api/review_checklist.md):]

Related Envoy Gateway issue:
envoyproxy/gateway#4625

I've tested this PR against AWS cognito using Envoy Gateway
SecurityPolicy, and it worked.

cc @missBerg @arkodg

---------

Signed-off-by: Huabing Zhao <[email protected]>
Signed-off-by: code <[email protected]>
Co-authored-by: code <[email protected]>
Co-authored-by: phlax <[email protected]>
(cherry picked from commit 0c6a1d2)
Signed-off-by: Huabing Zhao <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants