What is OAuth
Understanding OAuth Framework and its Vulnerabilities
# Table of Contents
# Introduction
In its essence OAuth is a standard for resource sharing between various applications (Authorization mechanism).
For example when a user logs in to example.com with their Github account it is done through Github's OAuth API, which grants example.com some access to the users Github account.
The user never gives example.com their credentials to Github
OAuth has two versions
- OAuth 1.0 (Legacy)
- OAuth 2.0 (Current Standard)
Version 2.0 was written from scratch, meaning that the difference between these two versions is colosal. From now on any mention of OAuth is refered to the 2.0 version.
# How Does It Work
OAuth works by defining a series of interactions between three distinct parties
- The Client Application (
example.comin this example) - The Resource Owner (the user)
- The Resource Provider (
Githubin this example)
There are many ways this process can be implemented. These are known as OAuth flows or grant types
# Grant Types
There are two most common grant types.
# What Is A Grant Type
The Grant Type (Flow) defines the exact sequence of steps that are involved in the OAuth process.
The grant type also affects how the client application interacts with the OAuth provider.
An OAuth service must be configured to support a particular flow before a client application can initiate a corresponding flow.
The application specifies the prefered flow in the initiating request to the OAuth service.
The two by far most common flows are authorization code and implicit.
# Authorization Code Grant Type
This grant type is used by confidential and public clients to exchange an authorization code for an access token.
At a high level the flow has the following steps:
- The application opens a browser to send the user to the OAuth server.
- The user sees the authorization prompt and approves the app's request.
- The user is redirected back to the return URL with an authorization code in one of the URL parameters.
- The application exchanges the authorization code for an access token.
# Step 1: Getting the users permission
The application needs to decide which permissions its requesting, then send the user to a browser to get their permission. To begin the authorization flow, the application constructs a URL like the following and opens a browser to that URL.
https://authorization-server.com/auth?response_type=code&client_id=123345456567678&redirect_uri=https%3A%2f%2fexample-app.com%2Fcallback&scope=create+delete&state=zsldkjf98230jsdOkay lets understand what each of these parameters do:
response_type=code- This tells the authorization server that the application is initiating the authorization code flow.client_id- The public identifier for the application, obtained when the developer first registered the application.redirect_uri- Tells the authorization server where to send the user back to after they approve the request.scope- One or more space-separated strings indicating which permissios the application is requesting. The specific OAuth API you're using will define the scopes that it supports.state- The application generates a random string and includes it in the request. It sholuld check that the same value is returned after the user authorizes the app. This is used to prevent CSRF attacks.
# Step 2: Redirection
After the user gives the requested permissions the authorization server redirects the user to the provided redirect_uri adding the following URL parameters to the redirect URI:
code- the authorization code generated by the authorization server. This code is usually short lived, around 1-10 minutes depending on the authorization server.state- the same state string provided by the client application to prevent CSRF and that type of attacks.
# Step 3: Getting the access token
Now the clinet application has an authorization code that it can exchange for an access token.
The application makes a POST request to the service's token endpoint with the following parameters:
grant_type=authorization_code- This tells the token endpoint that the applicaiton is using the Authorization Code grant type.code- The authorization code given by the OAuth serviceredirect_uri- The same redirect URI that was used when requesting the code. Some APIs don't require this parameter, so you'll need to double check the documentation of the particular API you're accessing.client_id- The application's client IDclient_secret- The application's client secret. This ensures that the request to get the access token is made only from the application, and not from a potential attacker that may have intercepted the authorization code. The token endpoint will verify all the parameters in the request, ensuring the code hasn't expired and that the client ID and secret match. If everything checks out, it will generate an access token and return it in the response.
Example response:
HTTP/1.1 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "<ACCESS_TOKEN>",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "<REFRESH_TOKEN>",
"scope": "create delete"
}Authorization complete. This is how the authorization code flow works. You can probably already see where can miss-implementation cause vulnerabilities. I'm not sure how ofter applications implement their own OAuth, but a single verification and validation issue can cause a lot of problems.
There are some other flows that need an explaination, so lets continue.
# Implicit Grant Type
Implicit grant type is much more simple than the Authorization code grant type.
It just skips the authorization code and directly asks for the access token.
The question is, why not use it everywhere?
Answer is really simple. Getting the access token right away gives room for various attacks.
Lets see how this flow goes.
- The client application requests user permission.
- After the user grants the permission, the OAuth provider redirects the user to the
redirect_uriwith the access token and related parameters in the URL. - After that the client application extracts the access token and gets the user info from the OAuth provider.
# Identification
So how do we identify which flow does the target application use?
As mentioned in the Authorization Code flow explaination, in Step 3 the client applicaton includes a grant_type parameter to the request. In case of authorization code, the value is code as observed earlier, and in case of Implicit, the value is token (it's really straight forward).
# Client Application Vulnerabilities
So as we learned about this whole OAuth thing, it's become obvious that a lot of things can be miss-implemented, as the OAuth framework doesn't really have built in security measures and many security checks are optional (some where discussed, like the state URL parameter).
An example of a miss-implementation that can cause serious damage is insufficient validation of the redirect_uri parameter that can lead to account takeover.
# Scenario N1: No Validation at All
An attacker crafts a link with modified redirect_uri parameter which points to the attacker controled web resource. When the user completes the authorization process the authorization code gets sent to the attacker controled resource which enables the attacker to request an access token from the OAuth provider and takeover the victim account.
# Scenario N2: Weak Regex Filter
If the redirect_uri is validated with a regex expression an attacker can satisfy the expression but still make the redirect_uri point to the attacker controled resource. Example for target.com and a regex that checks if target.com is present in the parameter would be:
redirect_uri=https://target.com@attacker.comredirect_uri=https://target.com.attacker.comredirect_uri=https://attacker.com/target.com
And so on and so forth.