oauthjs / node-oauth2-server

Complete, compliant and well tested module for implementing an OAuth2 Server/Provider with express in node.js
https://npmjs.org/package/oauth2-server
MIT License
4.02k stars 931 forks source link

Multiple Security Vulnerabilities in Auth and Token Endpoint #637

Open tamjidrahat opened 4 years ago

tamjidrahat commented 4 years ago

I would like to report several security vulnerabilities that I found while using this OAuth server library.

The vulnerabilities and their consequences are listed as following:

Vulnerability 1: Missing PKCE support for public clients.

Consequences: As specified in RFC-7636 (https://tools.ietf.org/html/rfc7636), public clients (e.g., mobile/desktop apps) using Authorization Code Flow are susceptible to authorization code interception attack and PKCE is recommended to mitigate this attack. Since public clients cannot maintain client-side confidentiality regarding client secrets, such attacks have been noticed in the wild extensively.

Vulnerability 2: Does not revoke previously issued token if authorization_code is used more than once.

Consequences: As specified in RFC-6749 (https://tools.ietf.org/html/rfc6749#section-4.1.2), If an authorization code is used more than once, the authorization server must deny the request and should revoke all tokens previously issued based on that authorization code. Though OAuth2-server currently denies the request in such cases, it doesn't revoke the tokens issued previously to the client, which leaves the user's resources vulnerable as attackers might exploit the previous tokens to get them.

Vulnerability 3: Allows fragment in the redirect URI.

Consequences: Many OAuth attacks regarding misuse of redirect uris have been observed in the wild. As specified in the RFC-6749 (https://tools.ietf.org/html/rfc6749#section-3.1.2), authorization server should not allow fragments in the redirect uri as it allows the attackers to exploit the redirect uri and hence intercept the auth_code/token.

Any comments or fixes regarding these vulnerabilities?

Thank you.

thomseddon commented 4 years ago

Hi there,

Thanks for the detailed work you've done here - ...

1) You are correct that this library does not implement PKCE / RFC7636. As RFC7636 is an extension, I think the claim in the Readme of "RFC 6749 compliant" is valid and not misleading and I also therefore wouldn't describe this as a "vulnerability" with the library per se. However, I do agree that it is desirable to support PKCE and we have a big PR that claims to do just this (#452) - I hope we can get that reviewed and merged soon, at which point I will update the readme to show that we support RFC 7636.

2) Authorization codes are invalidated after use via the revokeAuthorizationCode(code, [callback]) model method which is called here: https://github.com/oauthjs/node-oauth2-server/blob/0bbdcfeaaf0d73e06acc028cd0d009eafab70817/lib/grant-types/authorization-code-grant-type.js#L71-L73

This appears to me to conform to the spec, please let me know if I'm missing something.

3) When an Authorization code is generated, the getClient(clientId, clientSecret, [callback]) model method is invoked. One of the required parameters on the return object is redirectUris, which should be an array of strings. When generating the auth code, the given redirect uri is checked to ensure it exactly matches one of the values in this list. The creation and storage of these client.redirectUris is an exercise left to the implementor (clients & redirect uris are normally registered through a web interface on the application) and so it is at this point that the redirect uri should be stripped of any fragment components.

Perhaps it would be wise for us to make point out this requirement for the implementor to comply with the spec exactly in the documentation. I can also see there's a couple of places in the docs that show the redirectUris/redirectUri as being an optional parameter, whereas the library does actually require them, so there's a documentation issue there.

Again, please let me know if I'm overlooking something.

jaumard commented 4 years ago

This appears to me to conform to the spec, please let me know if I'm missing something.

The spec say not only authorisation code must be invalidated, but also the tokens issued from that autorisation code. From the spec:

If an authorization code is used more than once, the authorization server MUST deny the request and SHOULD revoke (when possible) all tokens previously issued based on that authorization code.

But the spec specify when possible so I guess we can't really call that a vulnerability, but that would be really nice to have

lemagicien00 commented 4 years ago

It is true that once the authorization code is exchanged for an access token, that code is revoked. which prohibits obtaining a new token with the same code.

However, what if the client requests a new authorization code, when it has already obtained an access token still valid? He will have a new authorization code and can exchange it for a new access token. This implies that the old access token is still valid and the client will no longer use it.

From my point of view, the access tokens should be revoked when client request a new authorization code.

What do you think about this?

Best regards.

soulchild commented 3 years ago

Am I understanding this correctly? The described vulnerability due to the missing PKCE feature only applies to mobile/desktop apps(!) which are able to register custom URI schemes in the OS, so that a malicious app can register itself for a URI scheme used by a legit app and receive the authorization code instead?

So, if the redirect URI is set to a custom URI scheme, e.g. mycustomapp:oauth/callback to re-open the app when the user has completed the authorization step, a malicious app could have registered for the mycustomapp URI scheme as well and steal the authorization code from the query parameters. At least that's how I understand the necessary preconditions in RFC-7636.

This does not apply to browser-based OAuth2 client applications, does it?

Uzlopak commented 2 years ago

I guess, you first call revokeAuthorizationCode and then check if the redirect_uri is valid.

Uzlopak commented 2 years ago

This is a small security issue if I understood bluebirds tap method correctly.

I think we should revoke the AuthorizationCode much much earlier, by moving the revokeAuthorizationCode call above the redirectUri check.

An attack on the authorizationCode grant is usually based on a malicious redirect_uri. So if the authorization code is valid, we load the token, then tap on validateRedirectUri, and if the redirect_uri is invalid, we error and we are not calling revokeAuthorizationCode. So the authorizationCode is still existing despite it was used already.