Cross-Origin Resource Sharing (CORS) is an essential part of modern web security. When configured correctly, CORS allows web servers to specify who can access their resources, but misconfiguration can leave applications vulnerable to attacks. This guide will walk you through what CORS is, common misconfigurations, how to test for them using Burp Suite, and how to fix them for various web application stacks.
What is CORS?
Cross-Origin Resource Sharing (CORS) is a security feature implemented in web browsers that controls how web pages from different origins interact with each other. By default, web pages can only make requests to the same domain they were loaded from (same-origin policy). CORS allows servers to specify which external domains (or origins) can interact with their resources.
How Does CORS Work?
When a web page makes a cross-origin request (such as an AJAX request), the browser sends a preflight request to the server using the OPTIONS
HTTP method. This request checks if the actual request is allowed. If the server allows the origin, it responds with appropriate headers, such as Access-Control-Allow-Origin
, and the browser proceeds with the request.
Common CORS Configurations
- Access-Control-Allow-Origin: Specifies which origins can access the resources.
- Access-Control-Allow-Methods: Specifies which HTTP methods are allowed (GET, POST, PUT, etc.).
- Access-Control-Allow-Headers: Specifies which headers can be used in the request.
- Access-Control-Allow-Credentials: Determines whether the browser should send cookies or authentication data along with the request.
- Access-Control-Max-Age: Defines how long the results of a preflight request can be cached.
Common CORS Misconfigurations
- Wildcard (*) in
Access-Control-Allow-Origin
: Using*
as the value forAccess-Control-Allow-Origin
means that any domain can access the resource. This is dangerous for APIs or applications handling sensitive data. - Allowing All Methods (
Access-Control-Allow-Methods
): Some applications may incorrectly allow all HTTP methods (GET, POST, PUT, DELETE, etc.), potentially exposing sensitive operations to unauthorized users. - Overly Broad
Access-Control-Allow-Headers
: Allowing all headers or including sensitive headers likeAuthorization
without proper checks could lead to credential theft. - Allowing Credentials with Wildcard Origin: If
Access-Control-Allow-Credentials
is set totrue
whileAccess-Control-Allow-Origin
is*
, the browser will block the request due to security concerns, but it’s still a misconfiguration. - Misconfigured Preflight Caching (
Access-Control-Max-Age
): Setting a longAccess-Control-Max-Age
can result in outdated CORS configurations being cached for longer than necessary, creating security risks.
How to Test CORS Misconfigurations Using Burp Suite
Testing CORS misconfigurations involves simulating different scenarios where attackers could exploit incorrect configurations. We’ll use Burp Suite and Burp Suite Collaborator to identify vulnerabilities.
Step 1: Set Up Burp Suite
- Ensure Burp Suite is set as your browser’s proxy.
- Use Intercept to capture requests and forward them to Repeater for manual modification.
Step 2: Testing for Wildcard Access-Control-Allow-Origin
- Open Burp Suite and capture a request.
- Send the request to Repeater.
- Modify the
Origin
header in the request to an arbitrary domain, e.g.,evil.com
. - Observe the server’s response and check if the
Access-Control-Allow-Origin
header reflects*
orevil.com
. - If the server allows
*
, it indicates a potential CORS misconfiguration.
Step 3: Testing with Burp Collaborator for Open Redirects
- In Burp Suite, use the Burp Collaborator to generate a custom domain.
- Replace the
Origin
header with this domain. - If the response includes your Collaborator domain in
Access-Control-Allow-Origin
, you can infer the vulnerability. - Use the Collaborator tab to check for any callbacks from the server.
Step 4: Testing Access-Control-Allow-Credentials
Misconfiguration
- Send a cross-origin request where
Access-Control-Allow-Credentials
istrue
. - Ensure that the
Origin
is set to a specific domain (not*
). - If both
Access-Control-Allow-Credentials: true
and a wildcardAccess-Control-Allow-Origin
are present, report the vulnerability as this is a serious security flaw.
Step 5: Testing Preflight Requests
- Use Repeater to send an
OPTIONS
preflight request with different combinations of HTTP methods, headers, and origins. - Analyze how the server responds to unauthorized methods or headers.
- Look for overly permissive responses in
Access-Control-Allow-Methods
andAccess-Control-Allow-Headers
.
Step 6: Testing for Multiple Access-Control-Allow-Origin
Headers
- Modify the
Origin
header to multiple domains (e.g.,https://example.com, https://evil.com
). - If the server responds with multiple
Access-Control-Allow-Origin
headers, it could indicate a misconfiguration. Some browsers handle multiple headers inconsistently, potentially allowing unauthorized domains to access sensitive resources.
Step 7: Testing for JSONP Hijacking
- Modify a legitimate
Origin
to include a malicious domain (e.g.,https://trusted.com.evil.com
). - Send the request and observe the response.
- If the application returns sensitive data in a JSONP format to the untrusted domain, it’s a severe vulnerability.
Step 8: Testing for Subdomain Takeover Vulnerabilities
- Identify any unused or unconfigured subdomains (e.g.,
subdomain.example.com
). - Attempt to take over these subdomains using services like Burp Suite Collaborator or manual DNS registration.
- Once taken over, modify the
Origin
header to use the compromised subdomain. - If the server trusts this origin, attackers can gain unauthorized access to resources.
Step 9: Testing for Flawed Regex in Access-Control-Allow-Origin
- Modify the
Origin
header to exploit regex patterns (e.g.,https://trusted.comevil.com
). - If the server mistakenly trusts this malicious origin due to improper regex, it indicates a misconfiguration.
How to Fix CORS Misconfigurations
Once vulnerabilities are identified, fixing them depends on the web stack and server configuration. Below are solutions for a wide range of popular platforms.
1. Fixing CORS in Node.js (Express)
- Ensure that you set specific domains for
Access-Control-Allow-Origin
:
const allowedOrigins = ['https://yourdomain.com'];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Credentials', 'true');
next();
});
2. Fixing CORS in Django
In Django, use the django-cors-headers package:
CORS_ALLOWED_ORIGINS = [
"https://yourdomain.com",
]
CORS_ALLOW_CREDENTIALS = True
3. Fixing CORS in Apache
In your Apache configuration:
<ifmodule mod_headers="" c="">
Header set Access-Control-Allow-Origin "https://yourdomain.com"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
Header set Access-Control-Allow-Credentials "true"
</ifmodule>
4. Fixing CORS in IIS
Use the web.config file to set CORS headers:
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="https://yourdomain.com" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
5. Fixing CORS in Nginx
In your Nginx config:
add_header 'Access-Control-Allow-Origin' 'https://yourdomain.com';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
6. Fixing CORS in Spring Boot (Java)
In Spring Boot applications, CORS can be configured at a global or controller level.
- Global configuration:
@Configuration
public class MyCORSConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://yourdomain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("Authorization", "Content-Type")
.allowCredentials(true);
}
}
7. Fixing CORS in Flask (Python)
In a Flask application, you can use the Flask-CORS extension to handle CORS.
- Secure CORS by allowing only specific origins:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins="https://yourdomain.com", allow_headers=["Authorization", "Content-Type"], supports_credentials=True)
@app.route("/resource")
def resource():
return "CORS-secured resource"
8. Fixing CORS in Ruby on Rails
For Ruby on Rails applications, use the rack-cors gem to configure CORS securely.
- Add the gem to your
Gemfile
:
gem 'rack-cors', :require => 'rack/cors'
- Configure CORS in
config/application.rb
:
config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'https://yourdomain.com'
resource '*',
headers: :any,
methods: [:get, :post, :options],
credentials: true
end
end
9. Fixing CORS in ASP.NET Core
For ASP.NET Core applications, configure CORS using middleware.
- In
Startup.cs
, add CORS configuration:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("MyCORSPolicy",
builder =>
{
builder.WithOrigins("https://yourdomain.com")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("MyCORSPolicy");
}
10. Fixing CORS in Tomcat
For Apache Tomcat, you can secure CORS via filters in your web.xml
configuration:
<filter>
<filter-name>CORS</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>https://yourdomain.com</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,OPTIONS</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,Authorization</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
11. Fixing CORS in Magento
Magento, a popular e-commerce platform, can be configured for CORS by editing the .htaccess
file (for Apache).
- Add the following lines to your
.htaccess
:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://yourdomain.com"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
Header set Access-Control-Allow-Credentials "true"
</IfModule>
12. Fixing CORS in Nginx (Advanced Example)
Nginx allows detailed CORS control, including varying configurations for different API endpoints:
location /api/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://yourdomain.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain';
return 204;
}
add_header 'Access-Control-Allow-Origin' 'https://yourdomain.com';
add_header 'Access-Control-Allow-Credentials' 'true';
try_files $uri $uri/ /index.html;
}
13. Fixing CORS in Jetty
For applications running on Jetty, configure CORS in your web.xml
:
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
<init-param>
<param-name>allowedOrigins</param-name>
<param-value>https://yourdomain.com</param-value>
</init-param>
<init-param>
<param-name>allowedMethods</param-name>
<param-value>GET,POST,OPTIONS</param-value>
</init-param>
<init-param>
<param-name>allowedHeaders</param-name>
<param-value>Content-Type,Authorization</param-value>
</init-param>
<init-param>
<param-name>allowCredentials</param-name>
<param-value>true</param-name>
</init-param>
</filter>
Conclusion
Ensuring a secure CORS configuration is a critical component of web security. Misconfigurations can expose applications to cross-origin attacks, including credential theft and data exposure. By thoroughly testing for CORS vulnerabilities using tools like Burp Suite and applying targeted fixes for each web application stack, you can significantly reduce the risk of cross-origin attacks. Each web framework and server has its own approach to CORS management, so it's essential to implement best practices specific to your environment. Always aim for the principle of least privilege when configuring CORS to ensure only trusted domains can access your resources.
Reach out to Seclinq team to help you secure your web application.