padlock on metal gate
Mon Apr 17

OAuth 2.0 Authentication Vulnerabilities

OAuth is a fascinating topic for the reason of how much it is to be implemented by numerous websites. However, this popularity makes it equally alluring to attackers who can exploit implementation errors. The consequences of such attacks can be devastating as the attacker may steal the user’s sensitive data or even take control of the user’s account completely.

In this article, we will explore potential security vulnerabilities that can arise from implementation errors in OAuth, so that we may gain a better understanding of how to avoid these pitfalls and prevent the attack. If you don’t know what OAuth is and how it works, we have covered a very detailed explanation that you can find [here](https://www.binaryte.com/blog/understanding-o-auth-2-0-and-open-id-a- comprehensive-guide).

OAuth for authentication

If you have read the article we mentioned before, you might think right now - isn’t the OAuth supposed to be used as authorization instead of authentication? It is true, and yes, OAuth is not intended for this purpose. Yet, lots of websites implement OAuth flow for user authentication and it works like the SAML-based Single Sign On (SSO). The problem with this approach is, there is no standard way to do this which can be seen as hacky, which opens up a much wider vulnerability.

Identifying OAuth authentication

The OAuth authentication often requires users to login with their social media account. But, to ensure whether a website is implementing OAuth authentication, it is always better to check the request by utilizing proxy tools to intercept requests. The first flow would be a request to /authorization endpoint, followed by several parameters such as redirect_uri, client_id, and response_type and this is a strong indication of a website using OAuth for authentication.

Example:

GET /authorization?
client_id=ab1234&redirect_uri=https://example.com/callback&scope=openid%20profile&response_type=token&state=xyzQWE123 HTTP/1.1

Exploiting Client Application

Improper implicit grant type implementation

Referring to our article of how the entire OAuth 2.0 workflow works, there is no standard way of how the client could obtain the user’s information. The implementation of OAuth may be going as follows.

  1. When the client application redirects users to the third party server (e.g. Facebook), users are sometimes given an option to login with their own social media with the purpose of identifying the client.
    Ideally, the client doesn’t need to know anything about the user identity at all. The idea behind the implementation of OAuth is anonymous resource sharing with third parties. Despite this, it is common for websites to identify the users, for example by storing their email address with their account in the client database.

  2. Hence, the client may also request for user information from a third party on the corresponding endpoint after taking the access token.

  3. Once the client has the user’s email (and probably some user’s profile information), the client may utilize the email as a substitution for username and the access token is often used as substitution for password.

This approach is bad as it allows the attacker to login to any user account without even knowing the victim’s password. Let us explain further what we mean.

  • Joe wants to sign in to a new website he just found, https://example.com. When clicking “Sign In”, a notification is telling him that he is now redirected to his social media account. In the background, the client is requesting the openid email for scope value to a third party server. A prompt then shows up, asking for his username/email and password.
  • Joe enters his email and password and then he is redirected to the application dashboard. After that, a prompt shows up asking for his consent regarding the access of his email to the client application.
  • When Joe’s is trying to logout and relogin, the application is redirected to his dashboard by using cookies stored in his browser. What he doesn’t know is that the client application includes his email to the request body along with the access token which works as a substitution for his password to the third party server for authentication.

The problem with this approach is that the credential sent by the client application can be intercepted by the malicious actor, allowing the attacker to deliberately change the email address to another one without having to change the access token. By doing so, it is possible for the attacker to authenticate to any registered account by solely using the corresponding email address.

Improper use of state parameter

In a previous article, we mentioned that the state parameter plays an important role for mitigating the risk in mitigating CSRF attacks. The state parameter should be an unguessable value and also unique for every session as it will be traversing back and forth during the entire flow.

OAuth is often considered a hacky solution for authentication, as it was not originally designed for this purpose. Some websites may offer two different options for authenticating users, using a classic form that requires username and password and social media authentication. Sometimes, the users are allowed to bind their social media account with their existing account.

How can the exploit be done?

Let’s focus on this case, where the users are given an option to link their social media account. Remember, when we are saying that OAuth is supposed to be anonymous? During the process of linking the account, the server will send code for binding the social media account.

Say that the attacker is trying to link his/her social media. Working on behalf of its user, the application can send requests to the server that contains several parameters: client_id, redirect_uri, response_type, and scope. Notice that we don’t even use state parameters here.

The server is responding with the code for linking the social media account. Supposedly, the server sends the state parameters along with this code. As the client doesn’t use it in the first place (and is not mandatory), no state is sent following the response.

As a result, using a CSRF technique, the attacker can craft his/her own request with the code to the victim. Without even realizing that the request is forged, the victim can be tricked to enter his/her credential. As the code used is bound with the attacker’s account and the one who authenticates the social media account is the victim, the server will think that everything is working correctly.

This is the reason why the state should be unique for every session and be hard to guess. If the client is using the state parameter which is basically a hash that contains a session cookie, this kind of attack can be prevented. By using a hash generated from session cookie, the client application should be able to use the same hashing method to identify what the state parameter value should be for the current session. If the attacker is trying to do the same thing, it won’t be effective due to the fact that the same state parameter is no longer usable for another session.

The code we have talked about earlier will be sent in the form of a URL like this.

https://example.com/oauth-linking?code=Y3dkGOI1ptnNiRayv8YJAOr3eWIXkUKXe7GPr9Jc36i

By implementing the state parameter, it should look like this.

https://example.com/oauth-linking?code=Y3dkGOI1ptnNiRayv8YJAOr3eWIXkUKXe7GPr9Jc36i&state=f2a1ed52710d4533bde25be6da03b6e3

The first URL is considered valid as long as it has not been used previously, no matter what the user session is. Because of this, the attacker may drop the request right before this URL is sent to the server. Later on, the attacker can craft a new request with this URL and send it to the victim so he/she can login to his/her social media. Due to the intended use of this URL for linking the attacker’s social media rather than the victim’s, the victim’s social media ends up being linked to the attacker’s account.

With a constantly changing state parameter on every session the attacker won’t be able to use the same technique. Assuming the attacker is forging a request the same way as before, it will be invalid once the victim is trying to login as the session is already changed.

Otherwise, the problem may persist if the state parameter is not changing. If the client only uses state parameters like “abcde” over and over again the result will be no better than having no the state parameter at all. This is what we mean by “improper use of state parameters”.

Exploiting OAuth Service

**Flawed redirect_uri validation **

In a previous article, we have also talked about how useless it is to steal the authorization code. Assuming that the OAuth implementation is following authorization code flow, this could be the case. In the real world application, it is common to simplify the OAuth process with implicit flow especially for authentication purposes. To put simply, the implicit flow allows the client application to immediately receive the code/token once the initial parameters (client_id, redirect_uri, etc) is sent.

The implicit flow works on the front channel only which is known to be less secure. If so, what if the server fails to validate the redirect_uri parameter properly and the attacker takes advantage of this vulnerability by inducing the CSRF-like attack? What if the attacker can successfully steal the code?

This is one of the most known attacks that take advantage of the flaw that is coming from the OAuth service itself. The simplification of implicit flow makes it very harmful if the attacker can somehow steal the code/token. In the previous example, the code is used for linking social media accounts. In fact, it also can be used to authenticate the users directly.

If the server fails to validate the redirect_uri, the attacker may arbitrarily change the value to any URI at will. By doing this, the attacker can redirect the victim to the attacker’s exploit server mimicking the actual client application. If the victim is not aware of this fake page, hence providing their credential, the attacker may steal the code being sent by the server. This code can be abused for authenticating the attacker simply by copying the original OAuth callback URL along with the given code into the attacker’s web browser.

Stealing code via open redirect

Sometimes the website developer implements validation that prevents redirection to the external domain on the redirect_uri parameter. However, it doesn’t mean that using CSRF attacks will no longer work. While this is the case, some other query parameters in the website may still be vulnerable, and the attacker may be able to supply the vulnerable to the redirect_uri using [directory traversal](https://binaryte.com/blog/exploiting-directory- traversal-vulnerability) technique.

Despite changing the following parameter like this: …&redirect_uri=https://binaryte.com/oauth-callback&scope=... into this: …&redirect_uri=https://evil.com/&scope=... , the attacker may change it to another path that is vulnerable within the application itself, like this:
…&redirect_uri=https://binaryte.com/../post/new- path=https://evil.com/&scope=...

In implicit grant type, the code will be sent in the form of a URL fragment. Because of this, the attacker may use their own controlled domain to steal the URL fragment. The sure way to do this is by exploiting the open redirect vulnerability.

Working as a proxy, this domain is used to forward the victims with the code or token to the domain controlled by the attacker. In this domain, the malicious script is running in the background to let the attacker parse the URL fragment which includes the actual code or token.

Again, this scenario may work assuming that the website is implementing the implicit flow. By simply stealing the code, the attacker could have access to the victim’s account on the client application. As this implicit flow is occurring on the client side only (front channel), fetching user’s sensitive data is way easier to do than the authorization code workflow which utilized both client side (front channel) and server side (back channel).

Flawed scope validation

Scope parameter defines the level of access granted to an application by the resource owner to certain resources. The token sent by the server limits what the application can do with the resource. Contrary to what people believe, this is actually possible for the client (or the attacker) to escalate this limitation and have extra access if the scope validation is somehow failing depending on the grant type.

Scope upgrade in implicit flow

Implicit grant type only takes place on the front channel and we know that the token is sent directly through the browser. While the OAuth server is expected to verify that the new scopes requested by the attacker match the original ones, this validation is not always performed. If so, the client (or attacker) may access additional data without the user’s consent.

Scope upgrade in authorization code flow

Unlike any other vulnerabilities we have talked about, this vulnerability takes place in secure server-to-server communication (back channel) which is considered secure. However, without proper scope validation, the attacker may request additional scope with the existing code or token.

Assumes that the attacker is controlling the client application. The initial request specifies the scope to only request the user’s email like this.

…&scope=openid%20email&state..

The resource owner then logs in with his credential and gives the consent of the resource that the client needs (which is the user’s email). When the client sends the request from the back channel, the attacker may attach extra scope such as profile or contact or anything which is supposed to be out of scope.

The request will look like this.

POST /token
Content-Type: application/x-www-form-urlencoded
Host: oauth-authorization-server.com
code=abc123def567
&client_id=ab1234
&client_secret=secret123
&grant_type=authorization_code
&scope=openid email profile contact

If the authorization server doesn’t validate this request, the new access token can be generated for this scope, instead of the initial scope. The authorization server will then return the following response instead allowing the attacker to extract more information from the resource owner which exceeds the user’s consent.

{
 "access_token":"b1f335be07a3deea0ff38150b1649f56",
 "token_type":"Bearer",
 "expires_in":3600,
 "scope": "openid email profile contact"
}

Preventing OAuth authentication vulnerabilities

The real disadvantage of using OAuth for authentication is there is no standard way of how the client can get user’s information. The reason is that the intended purpose of OAuth is authorization and not authentication.

Another concern regarding the implementation is that OAuth specification is meant to be flexible by design and lacking in terms of security measures. As a result, the security of the OAuth implementation heavily depends on the developers, which increases the likelihood of errors caused by misconfiguration or poor practices.

Because of this, the prevention and mitigation will be focused on the general implementation, the client application as the most vulnerable attack surface, and the implementation of OAuth service itself.

Flow implementation

Avoid using implicit flow

If you follow along until this point, you should be aware that most of the vulnerabilities we have learned involve the implicit workflow. At the time this article is written, the implicit flow is deprecated and it is recommended to use the authorization code flow with PKCE instead.

Comprehensive understanding of OAuth implementation

It is mandatory to fully understand how it works before implementing the OAuth for your application. Always follow the OAuth 2.0 implementation best practice which you can find [here](https://tools.ietf.org/html/draft-ietf-oauth- security-topics). Remember that this is very easy to get into bad practice which potentially causes vulnerability.

OAuth client application

Always use state parameter

Although a state parameter is not mandatory, we recommend using it for CSRF attack prevention. It is even better to make it unique for each session.

Validate id_token

To ensure that the OpenID Connect id_token is validated correctly, it is important to adhere to the specifications of JSON Web Signature, JSON Web Encryption, and OpenID.

OAuth service provider

Registering valid redirect_uri

Allows developers to register the redirect URL for their application. Then, the authorization server should be able to identify the request containing the redirect_uri based on the registered client_id parameter. In this way, no matter how the attacker could mimic the client_id with modified redirect_uri, it won’t be effective for the reason that the redirect_uri is supposedly already registered on the server.

Enforcing use state parameter

Knowing how important it is to use a state parameter to prevent CSRF-like attack, enforcing any client to use this parameter should be equally important.

**Recheck the requested scope access **

Verify that the access token granted to the third-party application is limited to the specific scopes that the user has granted permission for. The server has a responsibility to reject the request if the requested scope differs from the original scope that was requested when the client sent the code/token. As such, it is crucial to ensure that the code/token corresponds to the scope that was initially granted for the code/token.