CORS Misconfiguration and How to Test and Fix Them: A Comprehensive Guide

CORS Misconfiguration

September 21, 2024

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

  1.  Access-Control-Allow-Origin: Specifies which origins can access the resources.
  2.  Access-Control-Allow-Methods: Specifies which HTTP methods are allowed (GET, POST, PUT, etc.).
  3.  Access-Control-Allow-Headers: Specifies which headers can be used in the request.
  4.  Access-Control-Allow-Credentials: Determines whether the browser should send cookies or authentication data along with the request.
  5.  Access-Control-Max-Age: Defines how long the results of a preflight request can be cached.

 

Common CORS Misconfigurations

  1.  Wildcard (*) in Access-Control-Allow-Origin: Using * as the value for Access-Control-Allow-Origin means that any domain can access the resource. This is dangerous for APIs or applications handling sensitive data.
  2.  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.
  3.  Overly Broad Access-Control-Allow-Headers: Allowing all headers or including sensitive headers like Authorization without proper checks could lead to credential theft.
  4.  Allowing Credentials with Wildcard Origin: If Access-Control-Allow-Credentials is set to true while Access-Control-Allow-Origin is *, the browser will block the request due to security concerns, but it’s still a misconfiguration.
  5.  Misconfigured Preflight Caching (Access-Control-Max-Age): Setting a long Access-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

  1. Open Burp Suite and capture a request.
  2. Send the request to Repeater.
  3. Modify the Origin header in the request to an arbitrary domain, e.g., evil.com.
  4. Observe the server’s response and check if the Access-Control-Allow-Origin header reflects * or evil.com.
  5. If the server allows *, it indicates a potential CORS misconfiguration.

Step 3: Testing with Burp Collaborator for Open Redirects

  1. In Burp Suite, use the Burp Collaborator to generate a custom domain.
  2. Replace the Origin header with this domain.
  3. If the response includes your Collaborator domain in Access-Control-Allow-Origin, you can infer the vulnerability.
  4. Use the Collaborator tab to check for any callbacks from the server.

Step 4: Testing Access-Control-Allow-Credentials Misconfiguration

  1. Send a cross-origin request where Access-Control-Allow-Credentials is true.
  2. Ensure that the Origin is set to a specific domain (not *).
  3. If both Access-Control-Allow-Credentials: true and a wildcard Access-Control-Allow-Origin are present, report the vulnerability as this is a serious security flaw.

Step 5: Testing Preflight Requests

  1. Use Repeater to send an OPTIONS preflight request with different combinations of HTTP methods, headers, and origins.
  2. Analyze how the server responds to unauthorized methods or headers.
  3. Look for overly permissive responses in Access-Control-Allow-Methods and Access-Control-Allow-Headers.

Step 6: Testing for Multiple Access-Control-Allow-Origin Headers

  1. Modify the Origin header to multiple domains (e.g., https://example.com, https://evil.com).
  2. 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

  1. Modify a legitimate Origin to include a malicious domain (e.g., https://trusted.com.evil.com).
  2. Send the request and observe the response.
  3. 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

  1. Identify any unused or unconfigured subdomains (e.g., subdomain.example.com).
  2. Attempt to take over these subdomains using services like Burp Suite Collaborator or manual DNS registration.
  3. Once taken over, modify the Origin header to use the compromised subdomain.
  4. If the server trusts this origin, attackers can gain unauthorized access to resources.

Step 9: Testing for Flawed Regex in Access-Control-Allow-Origin

  1. Modify the Origin header to exploit regex patterns (e.g., https://trusted.comevil.com).
  2. 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.

You May Also Like…