Understanding Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) is a browser security mechanism that restricts web pages from making requests to a different domain than the one which served the web page. This restriction prevents malicious scripts on one website from accessing sensitive data on another website. While enhancing security, it often requires configuration to allow legitimate cross-origin requests, especially in modern web applications that frequently interact with APIs hosted on different domains or subdomains.
The CORS Mechanism
When a web page makes a request to a different origin (protocol, domain, or port), the browser automatically includes an Origin
header in the request. The server receiving the request can then inspect this header and decide whether to allow the request. The server communicates its decision by including the Access-Control-Allow-Origin
header in its response.
Here’s a breakdown of common Access-Control-Allow-Origin
values:
*
: Allows requests from any origin. While convenient for public APIs, it’s generally considered a security risk for sensitive data.<origin>
: Allows requests only from the specified origin (e.g.,https://www.example.com
).null
: Used for requests originating from file:// URLs or other contexts where no origin is present.
The Challenge: Handling Wildcard Origins and Subdomains
A common requirement is to allow requests from any subdomain of a particular domain, and potentially from different ports and protocols. The standard CORS specification doesn’t directly support wildcard subdomains using a simple asterisk (*
). You can’t use Access-Control-Allow-Origin: *
in production environments as it relaxes security too much. Instead, you need to dynamically determine the origin and echo it back in the Access-Control-Allow-Origin
header.
Dynamic Origin Handling with Apache
Web servers like Apache provide mechanisms to achieve this dynamic behavior. Here’s a robust approach using Apache’s mod_rewrite
and mod_headers
modules. This example demonstrates how to configure Apache to dynamically set the Access-Control-Allow-Origin
header based on the incoming Origin
header.
<IfModule mod_rewrite.c>
<IfModule mod_headers.c>
# Define the root domain that is allowed
SetEnvIf Origin .+ CORS_ALLOW_ORIGIN=$0
# Set the response header to the captured value if there was a match
Header set Access-Control-Allow-Origin "%{CORS_ALLOW_ORIGIN}e" env=CORS_ALLOW_ORIGIN
# Always add the Vary header for correct caching and spec compliance
Header merge Vary "Origin"
</IfModule>
</IfModule>
Explanation:
SetEnvIf Origin .+ CORS_ALLOW_ORIGIN=$0
: This line sets an environment variableCORS_ALLOW_ORIGIN
to the value of the incomingOrigin
header. The.
matches any character and+
indicates one or more occurrences. This captures the entire origin value.Header set Access-Control-Allow-Origin "%{CORS_ALLOW_ORIGIN}e" env=CORS_ALLOW_ORIGIN
: This sets theAccess-Control-Allow-Origin
response header to the value stored in theCORS_ALLOW_ORIGIN
environment variable. The%{}e
syntax tells Apache to use the value of the environment variable.Header merge Vary "Origin"
: This adds theVary: Origin
header to the response. This is crucial for caching. It tells caching servers that the response can vary based on theOrigin
header, ensuring that different clients receive the correct CORS headers.
Configuration Notes:
-
Ensure Modules are Enabled: Verify that
mod_rewrite
andmod_headers
are enabled in your Apache configuration. -
Placement: Place this configuration within a
<Directory>
or<VirtualHost>
block that corresponds to the resource you are protecting. -
Multiple Domains: To allow multiple domains, you can expand the
SetEnvIf
condition using regular expressions:SetEnvIf Origin "https?://(.+\.)?(othersite\.com|mywebsite\.example)(:\d{1,5})?$" CORS_ALLOW_ORIGIN=$0
This will allow origins from both
othersite.com
andmywebsite.example
.
Verification
After deploying these changes, verify the CORS configuration using a tool like curl
or your browser’s developer console. A sample curl
command:
curl -X GET -H "Origin: http://site1.example" --verbose http://site2.example/query
Examine the response headers to confirm that the Access-Control-Allow-Origin
header is set correctly to http://site1.example
.
Security Considerations
While dynamic origin handling offers flexibility, always prioritize security:
- Avoid
*
in Production: UsingAccess-Control-Allow-Origin: *
should be avoided in production environments. - Input Validation: If you’re using regular expressions to validate the origin, ensure they are robust and prevent potential injection attacks.
- Regular Audits: Regularly review your CORS configuration to ensure it aligns with your security policies.
By implementing these techniques and considerations, you can effectively and securely handle CORS requests from various origins, subdomains, ports, and protocols.