Configuring CORS for Secure Cross-Origin Requests

Configuring CORS for Secure Cross-Origin Requests

CORS (Cross-Origin Resource Sharing) controls how resources on your web server can be accessed from different domains. Proper CORS configuration balances functionality with security:

Apache CORS configuration:

<IfModule mod_headers.c>
    # Simple CORS for specific origin
    Header set Access-Control-Allow-Origin "https://trusted-domain.com"
    Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
    Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With"
    Header set Access-Control-Max-Age "3600"
    Header set Access-Control-Allow-Credentials "true"
    
    # Dynamic CORS based on origin
    SetEnvIf Origin "^https://(www\.)?(trusted-domain\.com|another-domain\.com)$" CORS_ALLOW_ORIGIN=$0
    Header set Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
    
    # Handle preflight requests
    RewriteEngine On
    RewriteCond %{REQUEST_METHOD} OPTIONS
    RewriteRule ^(.*)$ $1 [R=204,L]
</IfModule>

Nginx CORS configuration:

# Define allowed origins
map $http_origin $cors_origin {
    default "";
    "https://trusted-domain.com" $http_origin;
    "https://www.trusted-domain.com" $http_origin;
    "https://another-domain.com" $http_origin;
}

# CORS headers
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With" always;
add_header Access-Control-Max-Age 3600 always;
add_header Access-Control-Allow-Credentials "true" always;

# Handle preflight requests
if ($request_method = OPTIONS) {
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With" always;
    add_header Access-Control-Max-Age 3600 always;
    add_header Content-Length 0;
    add_header Content-Type text/plain;
    return 204;
}