CORS - Cross-Origin Resource Sharing
About 2 min read
CORS (Cross-Origin Resource Sharing) is an access-control mechanism for when a browser sends a request to a server on a different origin (a combination of domain, port, and protocol). It was published as a W3C recommendation in 2014 and is now implemented by all major browsers. Today, as the architecture of running a web application's frontend and backend on separate domains has become common, correctly understanding and configuring CORS is an essential skill for web developers. It is also a security mechanism closely related to CSRF and XSS.
Relationship with the Same-Origin Policy (SOP)
To understand CORS, you first need to know the Same-Origin Policy (SOP). The SOP is a browser security model introduced in Netscape Navigator 2.0 in 1995, with the constraint that "a script loaded from one origin cannot access resources of another origin."
Without the SOP, attacks such as a malicious site calling a bank site's API to obtain a user's account information would easily succeed. CORS is a mechanism for safely relaxing this SOP constraint. By having the server explicitly declare "I allow requests from this origin," it enables legitimate cross-origin communication.
How the Preflight Request (OPTIONS) Works
Before sending a cross-origin request that meets certain conditions, the browser sends a "preflight request" using the OPTIONS method. This is a mechanism for checking with the server in advance: "Will you accept this request?"
The conditions that trigger a preflight include the use of the PUT / DELETE / PATCH methods, Content-Type: application/json and other custom headers, and sending credentials (cookies). A GET request with no custom headers is treated as a "simple request," and the preflight is skipped.
Key CORS Response Headers
| Header | Role | Caveats |
|---|---|---|
| Access-Control-Allow-Origin | Specifies the allowed origin | The wildcard (*) cannot be used together with credentialed requests |
| Access-Control-Allow-Methods | Lists the allowed HTTP methods | Returned in the preflight response |
| Access-Control-Allow-Headers | Lists the allowed request headers | Explicitly state custom headers such as Authorization |
| Access-Control-Allow-Credentials | Allows sending credentials such as cookies | When true, * cannot be used in Allow-Origin |
| Access-Control-Max-Age | Number of seconds to cache the preflight result | If too long, configuration changes take effect slowly |
Common Misconfigurations and Their Risks
A setting that allows all origins. Appropriate for public APIs, but if set on an API that requires authentication, a malicious site can obtain a user's data. Because it cannot be combined with credentials, it does not work for APIs that use cookie-based authentication.
An implementation that returns the value of the request's Origin header directly in Allow-Origin. This effectively allows all origins, but because it can be combined with Credentials: true, it is more dangerous than *.
Setting Access-Control-Allow-Origin: null permits requests from sandboxed iframes and local files. It is exploited in attacks where an attacker calls an API from within an iframe.
The Relationship Between CORS and CSRF
CORS and CSRF are often confused, but they protect against different things. CORS is a mechanism by which the browser controls the reading of a response; it does not block the sending of the request itself (in the case of a simple request). In other words, even if you configure CORS correctly, it may not prevent request submission via a CSRF attack. CSRF mitigation requires a separate defensive layer, such as the token method or the SameSite cookie attribute. Defense in depth combined with CSP and SSL/TLS is important.
In services that use an API key, a misconfiguration of CORS can sometimes lead to the leakage of the API key. See also Browser Extension Security, Best Practices for API Key Management, and the Startup Security Checklist.Web API security books on Amazon are recommended for learning implementation patterns.
Was this article helpful?