- Intro
- OAuth: The key points
- Approach: Reviewing security of OAuth implementation in mobile app
- Checklist: Security assessment of OAuth implementation
- Conclusion
Intro #
Security requires managing risks with smart and controllable solutions. This OAuth security guide provides mobile developers and security engineers practical advice for mastering key security procedures and understanding OAuth mechanisms to protect application and user data. We will evaluate OAuth authorisation flows and token security, and will explain how to implement PKCE, protect against CSRF attacks and automate OAuth security verification.
What you get: A short checklist and practical advice for security assessment of mobile applications that use OAuth protocol for user authorisation.
OAuth: The key points #
Note: in this article, the term “OAuth” specifically refers to OAuth 2.0, OAuth 1.0 has been deprecated since 2012.
OAuth, which stands for “Open Authorisation”, is a delegation protocol that allows for secure authorisation via access tokens without the need for password sharing between applications and services.
OAuth simplifies user experience but introduces security risks due to its complexity. Developers should thoroughly understand its mechanisms and adhere to best security practices to make OAuth perform optimally for their apps.
Authorisation flow in mobile apps is similar to the one used for web server applications, but with two main differences:
- Mobile apps are considered OAuth public clients, and it is assumed that these apps cannot store secrets securely.
- Mobile apps handle redirection to service providers and back to the app in different ways. The opaque logic behind the mobile redirection mechanism is the root cause of the majority of security issues.
In the context of mobile apps, the OAuth flow typically involves the following steps:
- User Requests Access: The user initiates login action in the mobile app.
- App Redirects to Authorisation Server: The app redirects the user to the authorisation server of the service they’re trying to access, asking for permission.
- User Grants Permission: The user logs in (if not already) and approves the app’s request for access.
- Authorisation Server Redirects Back: After approval, the authorisation server redirects the user back to the mobile app with an authorisation code.
- App Exchanges Code for Token: The app exchanges the authorisation code for an access token by making a request to the authorisation server.
- Access Granted: The app uses the access token to make API requests on behalf of the user.
The main benefit of this flow is that the user’s login credentials are never shared with the mobile app, which is beneficial for both the user (privacy) and mobile app (data minimisation and decreasing risk profile).
Approach: Reviewing security of OAuth implementation in mobile app #
During a security review, it’s important to strike a balance in how deeply you investigate the authorisation flow. Here’s a structured approach to follow:
- Understand architectural decisions: Recognize the architectural choices made by the developers.
- Familiarise with protocols and SDKs used by the application and its backend.
- Clearly scope work: It’s not necessary to conduct in-depth penetration testing on third-party solutions, Service Providers, or the SDKs as a whole. Focus only on things that directly affect authentication flow and have not been assessed.
- Focus on data processing for authorisation: concentrate on how the target application stores, manages, and processes data crucial for authorisation – such as access and refresh tokens
Struggling with mobile application security?
Let’s start with a security assessment.
Understanding app authentication #
In scenarios where mobile applications operate without a backend server, it’s a common practice to embed client_id
and client_secret
directly within the app’s code. This method poses significant security risks, as these credentials can be easily extracted through reverse engineering.
Some service providers use client_id
and client_secret
merely as identifiers to differentiate between clients. However, others grant additional privileges based on these credentials, such as access to hidden API endpoints or relaxed rate limits for specific clients. This means that if these credentials are compromised, an attacker could potentially impersonate the app, gaining unauthorised access to sensitive information or services.
Check the OAuth page on security considerations of client_secret
usage.
For a detailed analysis of why OAuth API keys and secrets are vulnerable in mobile apps, you can refer to the article “Why OAuth API Keys and Secrets Aren’t Safe in Mobile Apps”.
Security recommendations: To identify potential vulnerabilities, monitor for the presence of client_secret
in network traffic from the app and app’s source code.
Intricate workflow behind app-based OAuth login #
During the OAuth’s login process, the app typically opens a web page, and there are a few methods to access it in mobile applications:
- Implementing WebView within the app.
- Launching the page in an external browser.
- Using ChromeCustomTabs or SafariViewController.
WebView OAuth advantages: #
- UI could be customised so that the web page looks and feels like part of the app.
- Opening pages is quicker compared to an external browser, as it occurs within the app’s process, eliminating the need for inter-process communication.
- WebView allows to clean cache when mobile developers have no control over headers returned from the OAuth Service provider.
WebView OAuth disadvantages: #
- Security concerns are prominent with WebView. Certain vendors, including Google, prohibit OAuth implementation via WebView.
- The primary risk is that a malicious app developer can intercept user credentials.
- Attempts to implement OAuth via WebView, by altering the user agent, contravene Google’s policies and are discouraged.
- WebView’s JavaScript execution within the app’s process poses additional security risks. If WebView is used, strict security measures should be implemented.
- Unlike browsers, WebView doesn’t share cookie storage, necessitating users to log in again, even if they’re already authenticated in the browser.
A quote from Section 8.12 of RFC 8252: OAuth for mobile and native apps:
“Native apps MUST NOT use embedded user-agents to perform authorisation requests and allow that authorisation endpoints MAY take steps to detect and block authorisation requests in embedded user-agents.”
Considering these security concerns, WebView is not recommended for OAuth implementation in mobile apps.
Browser-based OAuth advantages: #
- Straightforward process; the user’s interaction shifts from the app to an external browser, delegating security from an app to the system.
- The browser retains login information through cookies, streamlining the process for users already logged into the service.
- The browser shows the URL and a TLS verification lock icon, reassuring users about the security of the page they are viewing.
Browser-based OAuth disadvantages: #
- Using an external browser is more resource-intensive for the applications.
- Lack of UI customisation, as the external browser operates independently of the app.
- Switching to the browser interrupts the app’s navigation flow.
- Traffic coming from browsers is more susceptible to interception.
- The cookies or session data might be cached in the browser, even if the user has pressed the “logout” button in the app, as the app doesn’t have a way to communicate to the browser that the session should end.
ChromeCustomTabs and SafariViewController advantages: #
ChromeCustomTabs and SafariViewController tools blend elements of browsers and WebView, providing a more balanced approach.
- They reduce the risk of data interception, a notable concern with WebView.
- They allow users to remain within the app while browsing, increasing engagement and reducing the risk of users abandoning the app.
- In contrast to WebView, JavaScript execution occurs outside the app’s process, reducing risks.
ChromeCustomTabs and SafariViewController disadvantages: #
- Unlike external browsers, which can share sessions and cookies with other browser instances, Chrome Custom Tabs and SafariViewController might not share the same level of session continuity. This can impact the ease of OAuth flows, and make development harder.
- UI customisation options are limited for these interfaces.
Additionally, Android supports Trusted Web Activities, which extend the Custom Tabs protocol and shares most of its benefits. However, it is inconvenient to implement in the context of OAuth.
Overall, ChromeCustomTabs and SafariViewController present a more optimal solution, addressing most drawbacks associated with WebView and external browsers.
Security recommendations for initiating the OAuth flow #
- Avoid using WebViews as it is susceptible to credential interception. When the external browser or ChromeCustomTabs/SafariViewController is used, secure redirections and data transfers prevent potential interception.
- Developers should weigh the trade-offs between user experience, app functionality, and security when choosing the method for integrating OAuth login. Each approach has its unique advantages and limitations, and the decision should align with the overall security posture and user experience goals of the app.
Handling redirects back to the mobile app #
Mobile application mechanisms of browser-to-app redirection are more susceptible to an authorisation code interception attack. In this attack, the malicious actor intercepts the authorisation code received from the authorisation endpoint via a non-TLS communication path, such as Inter-Process Communication(IPC) within the smartphone operating system.
Once the attackers get the authorisation code, they can use it to obtain access tokens.
In the context of OAuth implementations, the browser-to-app redirects commonly use mechanisms like Custom URI Scheme and AppLink. However, these methods do not offer the same level of security as the redirection mechanisms used in browsers.
Custom URI scheme #
Custom URI Schemes (also known as Deep links) are defined by developers before deployment, with no restrictions on the scheme’s format. A single device can host multiple apps with identical schemes. Using Deep links is easy when each scheme is unique to one app, but complications arise if multiple apps on a device register the same scheme.
- On Android, a conflict results in a prompt for the user to choose the intended app.
- iOS lacks a clear-cut process for resolving such conflicts, leading to unpredictable app launches. This ambiguity creates opportunities for attackers to intercept authorisation codes or access tokens.
Authorisation codes are most vulnerable during browser-to-app redirects, that’s why secure implementation of deeplinks is required. For more general information on deep link testing refer to Android and iOS OWASP MAS guides.
AppLinks #
AppLinks are web links that use the HTTP and HTTPS schemes and contain the autoVerify
attribute. This attribute allows your app to designate itself as the default handler of a given type of link. Applink aims to ensure that the correct application is opened, but it faces several challenges:
- Every client using the service must complete a verification process.
- Users can disable AppLink for specific apps in their Android settings.
- AppLink is unsupported on Android versions earlier than 6.0 and iOS versions before 9.0.
These limitations with AppLinks can potentially lead to OAuth failures under certain conditions. Consequently, many developers are hesitant to replace traditional browser redirects with the AppLinks.
Security testing of OAuth redirects #
- Scheme conflicts: Ensure there are no conflicts with Custom URI Schemes or possibilities for misuse. Pay particular attention to how different operating systems handle scheme conflicts, especially on iOS where the process is less transparent. If deep links are used, then verify that PKCE flow and state parameters are used.
- Verify AppLinks setup: If using AppLinks, verify that the setup is correctly implemented and adheres to the necessary verification procedures. Be aware of its limitations across different Android and iOS versions.
OAuth security improvement with PKCE #
The Proof Key for Code Exchange (PKCE) extension is an essential security measure in OAuth, particularly for mobile applications. Its primary role is to mitigate the risks associated with intercepting authorisation codes in public or insecure channels.
PKCE adds additional parameters like code_challenge
and code_verifier
to the authorisation code grant flow:
More details on how to protect the authorisation Code can be found in section 8.1 of RFC 8252: OAuth for Mobile and Native Apps
Without PKCE, attackers can exploit the OAuth authorisation code flow in a few ways:
- Authorisation code interception: Attackers could intercept the authorisation code as it travels from the authorisation server to the client. Without PKCE, possession of this code could allow unauthorised access to protected resources.
- Cross-site request forgery (CSRF): PKCE adds an additional layer of protection against CSRF attacks by ensuring that the party exchanging the authorisation code for an access token is the same party that initiated the authorisation request.
In the absence of PKCE, mobile apps are vulnerable to these attacks, potentially leading to unauthorised access and data breaches.
It should be noted that authorisation code interception attacks will not work if the app is using universal links (iOS) and app links (Android). To open a redirect link in an application, developers need to put a JSON file with a description of their application’s signature on the server. But often it is not possible to add the JSON file to the server if the app authorises using an external service that is not part of the app’s ecosystem. So if an application is using Universal links or AppLinks, the absence of PKCE can not be exploited, but following defence-in-depth principle it’s still recommended to implement PKCE flow if it’s possible. Additionally, by following this recommendation, there will be fewer “No PKCE ’’ issues reported.
Security recommendations for PKCE #
When testing whether the PKCE flow is securely configured, consider the following key points:
- Validate code challenge and code verifier: Ensure that the
code_challenge
andcode_verifier
are properly validated by the backend. Thecode_verifier
should be a high-entropy cryptographic random string, and thecode_challenge
should be a derivative of this string (typically using SHA-256). - Check code challenge method: The server should enforce the use of S256 (
code_challenge_method
) as the code challenge method. This method uses SHA-256 hashing, which is more secure than the plain method. - Verify client authentication: Ensure that the client authentication is enforced when exchanging the authorisation code for an access token. This verifies that the token is issued to the legitimate client.
- Inspect redirect URI: The redirect URI should be consistent and securely validated on the server side. Any discrepancies in the redirect URI validation can be a potential vulnerability.
- Test for leakage of code verifier: Ensure that the
code_verifier
is not exposed in any part of the communication, particularly in logs or error messages.
For more PKCE security considerations follow the link.
CSRF attacks mitigation with “state” parameter #
The state
parameter’s primary function is to maintain state information and provide CSRF protection. While PKCE secures the token exchange process, the state
parameter secures the initial authorisation request. Without the state
parameter, an attacker could trick a user into initiating an OAuth request that benefits the attacker, like authorising access to the user’s data.
Here is how Google recommends to properly obtain an access token to Google APIs. Notice that Google recommends using both PKCE and state
parameters.
State
parameter implementation is also recommended by Section 8.9 of RFC 8252: OAuth for mobile and native apps
Security verification of “state” parameter usage #
When testing the implementation of the state
parameter in mobile apps, consider the following key points:
- Ensure state parameter use: Verify that the
state
parameter is being used in the OAuth authorisation request. - Validate state value: The
state
parameter should be a unique and non-guessable value for each session. Ensure that this value is validated upon the redirection to the app after authentication. - Check for consistency: The state value sent in the OAuth request should match exactly with the state value received with the authorisation response. Any mismatch should be treated as a potential security threat.
- Test different scenarios: Conduct tests in various scenarios, including normal flow, interrupted flows, and scenarios simulating attack attempts (like modifying or replaying the state value).
Automation, automation, more automation #
We recommend using OAUTHScan, which is a Burp extension to verify the security of OAuth and OpenID flows. It has checks for the following scenarios:
- Open Redirect issues on the Redirect_Uri parameter
- Authorisation Code Replay issues
- Leakage of secrets (i.e. Tokens, Codes)
- PKCE misconfiguration
- Nonce parameter misconfiguration
- State parameter misconfiguration
- Input Validation issues on Scope parameter
- Detection of inherently insecure Flows
- SSRF issues via Request_Uri parameter
- Detection of Well-Known and WebFinger resources
While this extension is not a silver bullet for OAuth security assessment, it’s still useful to support manual review.
Checklist: Security assessment of OAuth implementation #
There is a checklist for testing OAuth implementation in mobile apps, divided into four groups.
General
- Verify that HTTPS is used everywhere, and a downgrade to HTTP is forbidden.
- Verify that recommended cryptographic signing and encryption algorithms are optimal and not outdated (see ES256, ECDH-ES and consult JSON Object Signing and Encryption).
- Verify that developers are not implementing their own OAuth scheme.
- Verify that the application uses Authorisation Code grant OAuth flow.
- Review for the common OAuth vulnerabilities. Mobile OAuth extends the original, although the correct
redirect_uri
validation and other criteria for the original OAuth remain in place. - Verify that
client_secret
is not used, or at least that there is not too much trust put in it, for example, it can be used merely as an identifier.client_secret
is useless unless it’s stored in the backend.
Storage
- Verify that
access_token
andreftesh_token
are stored in Keychain for iOS and encrypted in SharedPreferences for Android.
OAuth login handling
- Verify that the app uses Browser Custom Tab or External Browser, unless its functionality directly requires WebView usage, for example, when cleaning cache on the client side is mandatory
- Verify that redirection back to the mobile app is properly handled: the app validates the incoming URL and has no conflicts with Custom URI Schemes.
- Verify that if the app uses a service from its ecosystem (developed by the same company), universal links (iOS) and app links (Android), and the corresponding Digital Asset Links JSON file is published. More in Verify App Links.
Сode grant flow security
- Verify that the mobile app and backend implement PKCE flow to defend against code interception attacks. Additionally, verify that
code_challenge
andcode_verifier
are properly validated during the code-token exchange. Thecode_verifier
should be a high-entropy cryptographic random string, and thecode_challenge
should be a derivative of this string (typically using SHA-256). - Verify that the
state
parameter is used to defend against OAuth CSRF. - Verify that
code
can be used only once, with a short lifespan.
Conclusion #
The OAuth protocol is tricky to implement correctly for mobile applications and their backends, as it has many moving parts.
By following the advice above , you can ensure a secure and seamless experience for your users. Please bear in mind that key practices include mastering PKCE and the state parameter, choosing the appropriate login method, handling redirections carefully, and using external tools to identify low-hanging fruits before focusing on the deep review. The Cossack Labs team is here to support you in building secure applications—feel free to reach out for assistance and advice!