nzoschke / gofaas

A boilerplate Go and AWS Lambda app. Demonstrates an expert configuration of 10+ AWS services to support running Go functions-as-a-service (FaaS).
Apache License 2.0
800 stars 43 forks source link

Google OAuth 2.0 "state" #55

Open nzoschke opened 6 years ago

nzoschke commented 6 years ago

A reviewer reminded me of The Most Common OAuth2 Vulnerability

How to detect, is certain OAuth implementation vulnerable?

If site doesn't send 'state' param and redirect_uri param is static and doesn't contain any random hashes - it's vulnerable.

Reviewing the implementation, there is no "state" parameter on the OAuth redirect or callback.

Digging into the Passport code, it looks like state isn’t enforced. It’s ok if it isn’t provided and also ignored if there isn’t a session store configured. I don’t have a session store configured, since that's more of an Express.js thing.

https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L204

Here’s the some Google guides that talks about state.

https://developers.google.com/identity/protocols/OAuth2WebServer https://developers.google.com/identity/protocols/OpenIDConnect#state-param https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken

So I think we need to come up with a Lambda@Edge friendly way to set “state” and verify it….

nzoschke commented 6 years ago

The challenge w/ Lambda@Edge is that its stateless, so it's not obvious how to do a session store that's shared between Lambda funcs.

We could use a service like ElastiCache or DynamoDB but that feels like overkill.

Does the AUTH_HASH_KEY offer a way to generate a signed state value that can't be forged?

Maybe CloudFront headers offer a reasonable session identifier for a given user?

nzoschke commented 6 years ago

Here's an experiment for using JWT for the state parameter with stateless clients:

https://tools.ietf.org/html/draft-bradley-oauth-jwt-encoded-state-08#section-4.2

These clients can generate a hash value based on a HTTPS: bound session cookie or other browser side information that is not accessible to third parties. This hash value can be used as the value of "rfp".