OAuth is the widely used standard for access delegation, enabling many of the “Sign in with X” buttons and “Connect your Calendar” features of modern Internet software. OAuth 2.0 is the most common and recent version of this specification, which defines four grant types (as well as various extensions), specifically suited for different use cases.
As a security consultancy, we frequently encounter OAuth flows as one small component of the assessment of an application. As a result, we developed the desire for a comprehensive and digestible enumeration of security concerns in the OAuth 2.0 Authorization Code flow, from an end-user (or penetration tester)’s external vantage.
This post will introduce, break down the observable vulnerabilities, and explain the exploitation of each the following aspects of the Authorization Code flow:
state
code
redirect_url
client_secret
- Access Token
- Clickjacking
While numerous resources have been published on OAuth 2.0 security, none we found met our specific needs. Check out all the linked references, as they overlap with much of the information in this post, as well as a deeper dive into other aspects of OAuth 2.0 security!
Sidebar: While this post is discussing the Authorization Code grant, it still bears mention to keep an eye out for any usage of the Implicit flow or Password flow – these are legacy and considered generally insecure.
Let’s start with a brief history of OAuth:
2006: OAuth is started to fix an identified lack of an “open standard for API access delegation”
2007: The first draft of the OAuth specification is released
2009: A session fixation attack is discovered and disclosed
2009: OAuth 1.0a is issued to address the vulnerability
2010: OAuth 1.0 is published as RFC 5849
2012: OAuth 2.0 is published as RFC 6749, it is not backwards compatible with 1.0
2012-2013: OAuth 2.0 Threat Model and Security Considerations is developed as RFC 6819
2017-: OAuth 2.0 Security Best Current Practice has been through 15 drafts
We most commonly encounter the Authorization Code grant on client engagements. It is generally used by both web and native applications to retrieve an access token after a user authenticates to the third-party app. Generally, an app using this grant type will launch a browser to begin the flow.
Terminology
We will be using the formal terminology from the OAuth 2.0 specification throughout this post. A detailed breakdown of the terminology can be found on the oauth.com Terminology Reference:
The Resource Owner “the user”: This is the person who is granting some level of access to their account, data, services, or other access controlled resources.
The Resource Server “the API”: This is the server that contains the Resource Owner‘s data, which the third-party application is looking to access.
The Client “the application”: This is the application that will be accessing protected resources from the Resource Server on behalf of the Resource Owner.
Authorization Server: The server issuing access tokens to the Client. This is the server that generally displays the OAuth prompt, allowing the user to accept or deny the request.
Authorization Code grant flow
In the Authorization Code grant, the Client ultimately exchanges an authorization code for an access token. To start this flow, the Resource Owner makes a request to the Client. The Client then redirects the Resource Owner to the Authorization Server, passing a client_id
, stat
e, and redirect_uri
. After the Resource Owner authenticates, the redirect_uri
is passed by the Authorization Server back to the Resource Owner along with a code. The Resource Owner then passes the code to the redirect_uri
(which should be on the Client). The Client can then use the code
, in conjunction with the client_id
and client_secret
to retrieve the access code.
The security benefit of this grant type includes the ability to authenticate the Client (via the client_secret
), and the fact that the access token is never directly exposed or transmitted to the Resource Owner, limiting the chances of its compromise.
A detailed diagram of the flow, from “A Comprehensive Formal Security Analysis of OAuth 2.0” (Fett, Küsters, Schmitz) follows. Note, in the diagram the Resource Owner is referred to as the Browser, the Client as “RP,” and the Authorization Server as “IdP”:
Sidebar: Want another explanation of the flow? Go checkout Okta’s “Illustrated Guide” and then circle back here!
Attacking OAuth 2.0
Here are the common attack vectors against an OAuth 2.0 Authorization Code grant flow, presented according to the aspect of the flow which they target. Some of these issues arise from a lack of specificity in the original OAuth 2.0, while others represent common patterns of misimplementation. These vulnerabilities may be introduced by either the Client or the Authorization Server, however that has little bearing on their initial identification and exploitation:
state:
Usage:
The state
parameter was introduced to mitigate CSRF attacks. While it is RECOMMENDED
but not REQUIRED
in the specification, it should always be used. The state
functions as follows:
1. The Client generates a random string, and it is included the authorization request as the state
parameter. This value should also be stored in a location accessible only to the Resource Owner – commonly as a cookie or in browser local storage.
2. The Authorization Server redirects the Resource Owner back to the Client, and includes the exact provided state
.
3. The Client must verify the validity of the request by matching the returned state
to the Resource Owners’s stored value.
Exploitation:
To exploit any issue with state, you’ll be performing a CSRF attack. In short:
- An attacker can go through the grant flow, dropping the final request by the Resource Owner (where the code is presented to the Client)
- As in a CSRF attack, the attacker must coerce the victim’s browser into sending the dropped request in their stead
- Once the victim has sent the request, their account on the resource provider will be associated with your account on the authorization provider, frequently leading to account takeover
What to look for:
There are a number of common implementation flaws for the state
parameter in OAuth 2.0. When testing an OAuth 2.0 flow, always check:
- Lack of
state
– as described above, thestate
parameter is mandatory to prevent CSRF attacks. If you observe an OAuth 2.0 Authorization Code grant flow that entirely lacks this parameter, it is highly likely to be vulnerable. state
not required – try to simply drop thestate
parameter from the authorization request, and make sure the application is properly mandating its usage.state
not validated – try modifying thestate
provided by the client to the resource provider, to ensure the client validates it matches the original provided state.- Predictable
state
– often, applications misuse thestate
parameter to pass values through the flow. One use case for this is havingstate
partially or fully determine the redirect. While this can be done correctly (generally by appending the data to the randomstate
), it can result in a predictable state. state
fixation – while rare, we have observed applications that allow a user-providedstate
to initialize the OAuth 2.0 flow. This be exploited by an attacker who first fixes thestate
, and then coerces the victim to enter the OAuth 2.0 with the now-predictable state.
Sidebar: The PKCE
extension to OAuth 2.0 can be used in place of the state
parameter. PKCE
is defined in RFC 7636.
code:
Usage:
The code
parameter contains the authorization code received from the authorization server by the Resource Owner. The Resource Owner then presents this to the Client, which can use it to retrieve an access_token
from the Authorization Server. The access_token
can then be used to access the protected resources on the Resource Server.
Exploitation:
Generally, issues identified with the code
require a second vulnerability, exposing the code, to exploit. See the discussion of redirect_uri
exploitation below.
What to look for:
The most common vulnerability found with code
implementations is susceptibility to replay attacks. Consider the following test cases to ensure the flow is hardened against such attacks:
- Limited validity period: The
code
should only be usable for 5 to 10 minutes for the time of issue. - Reuse: The
code
should only be usable once. Consider race conditions on submission as well. - replay attacks: Upon attempted reuse of the
code
all access tokens previously issues based on thecode
should be revoked, as it is an indicator ofcode
compromise.
redirect_uri:
Usage:
As per the spec, “After completing its interaction with the resource owner, the authorization server directs the resource owner’s user-agent back to the client. The authorization server redirects the user-agent to the client’s redirection endpoint previously established with the authorization server during the client registration process or when making the authorization request”
Exploitation:
Exploitation of the redirect_uri
relies on manipulating providing a “poisoned” authorization request to the victim, which contains an attacker-controlled domain as the redirect URL. Once the victim authenticates, they will be redirected to the attacker-controlled domain. This redirect will include the cod
, which the attacker can then us to access the victim’s account.
If code
reuse is also allowed, this could in-fact be done transparently, as an attacker could simultaneously gain a session to the victim’s account, and also authenticate the victim.
What to look for:
The redirect_uri
is likely the most exploited aspect of the OAuth 2.0 flow. Consider the following cases when testing an OAuth 2.0 flow:
- No validation on
redirect_uri
: you will be able to exploit withattacker.com
as theredirect_uri
- Partial validation on
redirect_uri
domain: applications have endless implementations of validation forredirect_uri
, the following are common lapses in that validation:evilmatch.com
– application fails to anchor the domain pattern at the beginning of the domainmatch.com.evil.com
: application fails to anchor the domain pattern at the end of the domainevil.com#match.com
,evil.com?match.com
: application fails to properly parse URLmatchAmatch.com
– application fails to escape wildcard in pattern that includes subdomain.match.com.mx
: application fails to validate full TL
- IDN homograph normalization: some applications inconsistently normalize IDN homographs, using the normalized version for validation, but redirecting to the original domain. (ex. https://hackerone.com/reports/861940)
- Arbitrary paths allowed in
redirect_uri
: in this case, there are a number of vulnerabilities or cases that can be chained with theredirect_uri
, including:- Cross-site scripting
- Open redirect
- Page with a user-controlled third-party inclusion (such as a user profile with link to a photo). This can be mitigated if the site strips the Referer header.
- Partial validation on paths allowed in
redirect_uri
: directory traversal tricks can be used to bypass validation on the path in theredirect_uri
. - Arbitrary subdomains allowed in
redirect_uri
: subdomain takeovers can lead to compromise. If arbitrary paths are also allowed, any of the vulnerabilities discussed in (3), on any subdomain, can be used. redirect_uri
allows cleartext protocols: if theredirect_url
does not properly requirehttps
, the OAuth flow is opened to exploitation in the case of a MITM attack.
client_secret
Usage:
In the OAuth 2.0 specification of the Authorization Code grant, the client_secret
is a value unique to every resource provider, that allows it to valid code
s (with state, if required) for access tokens.
Exploitation:
The Authorization Code grant type was not initial designed for use in mobile or native applications, which frequently have no way to securely store the client_secret
. If the secret is leaked, an attacker who compromises a valid code
can escalate access by retrieving an access token for that user.
Sidebar: The PKCE extension effectively removes the need for a client_secret
. For a full discussion of PKCE, see Pragmatic Web Security’s blog post.
What to look for:
An application using the Authorization Code grant must keep the client_secret
confidential or use PKCE. If a mobile application or native application is using this grant type, you can likely retrieve the client_secret
from the application package.
Access Token
In the Authorization Code grant flow, the access token should never be exposed to the client, only used by the resource provider. Some common places the access token is accidentally disclosed include:
- In requests, stored in the browser history
- In transit, accessible to a client who is proxying traffic
- In JavaScript objects or state
- In browser local storage
The Authorization Code grant is designed to enable the Client to opaquely use the access token, without ever exposing it to the Resource Owner. This is built into the specification to reduce the chance of access token compromise. Any exposure of the access token is therefore a direct violation of the specification.
Clickjacking
While somewhat perpendicular to the actual Authorization Code grant flow, clickjacking is a major threat, and has been highlighted in both the Security Best Current Practice draft, as well as in the Threat Model. Authorization servers must prevent clickjacking attacks. The “X-Frame-Options” header is the legacy mitigation for clickjacking, while the Content Security Policy frame-ancestors
directive is a more modern control.
Sidebar: Check out our Clickjacking PoC tool. See here for a case where a $5,000 bug bounty was paid for this issue.
Thank you to Victor Magierski for assistance in editing this post!
References:
- https://twitter.com/hackerscrolls/status/1269266750467649538?s=20
- https://maxfieldchen.com/posts/2020-05-17-penetration-testers-guide-oauth-2.html
- https://pragmaticwebsecurity.com/files/cheatsheets/oauth2securityfordevelopers.pdf
- https://tools.ietf.org/html/draft-ietf-oauth-security-topics-15
- https://link.springer.com/book/10.1007/978-3-030-36938-5 (OVERSCAN)
- https://arxiv.org/pdf/1601.01229v4.pdf
- https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type
- https://oauth.net/2/grant-types/authorization-code/
- https://i.blackhat.com/asia-19/Fri-March-29/bh-asia-Wang-Make-Redirection-Evil-Again.pdf
- http://homakov.blogspot.com/search?q=oauth