CORS Misconfiguration
Cross-origin resource sharing (CORS)
Cross-origin resource sharing (CORS) is a browser mechanism which enables controlled access to resources located outside of a given domain. It extends and adds flexibility to the same-origin policy (SOP).
The same-origin policy is a restrictive cross-origin specification that limits the ability for a website to interact with resources outside of the source domain
The CORS standard works by adding new HTTP headers that let servers describe which origins are permitted to read that information from a web browser. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin from its own.
Origin is the following triple: (scheme, host, port)
For HTTP request methods that can cause side-effects on server data, the specification mandates that browsers preflight the request, soliciting supported methods from a server with the HTTP OPTIONS
request method, and then, upon approval from a server, sending the actual request.
Servers can also inform clients whether credentials should be sent with requests.
CORS failures result in errors, but specifics about the error are not available to JavaScript.
Simple requests
Simple requests do not trigger a CORS preflight. A simple request is one that meets all the following conditions:
One of the allowed methods:
GET
HEAD
POST
The only allowed headers which can will be set manually:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Downlink
Save-Data
Viewport-Width
Width
The only allowed values for the
Content-Type
header:application/x-www-form-urlencoded
multipart/form-data
text/plain
No event listeners are registered on any
XMLHttpRequestUpload
object used in a request (these are accessed using the XMLHttpRequest.upload property).No ReadableStream object is used in a request.
Preflighted requests
Preflighted requests first send a HTTP request by the OPTIONS
method to a resource on an other domain, to determine if an actual request is safe to send.
Requests with credentials
Credentialed requests allow to send HTTP cookies and HTTP Authentication information (by default browsers will not send credentials).
When responding to a credentialed request, a server must specify an origin in a value of the Access-Control-Allow-Origin
header, instead of specifying the '*'
wildcard.
Cookies set in CORS responses are subject to normal third-party cookie policies
The HTTP request headers
This section describes headers that a client may set when issuing HTTP requests in order to make use of the CORS feature. These headers are set by a browser when making requests to a server. Developers using cross-site XMLHttpRequest
capability do not have to set any CORS headers programmatically.
Origin
The Origin
header indicates an origin of a cross-site access request or preflight request. The origin
parameter is a URI indicating a server from which the request initiated. It does not include any path information, but only a server name.
The origin value can be null, or a URI
In any access control request, the Origin
header is always sent
Access-Control-Request-Method
The Access-Control-Request-Method
is used when issuing a preflight request to let a server know what HTTP method will be used when an actual request is made.
Access-Control-Request-Headers
The Access-Control-Request-Headers
header is used when issuing a preflight request to let a server know what HTTP headers will be used when an actual request is made.
The HTTP Response Headers
This section describes HTTP response headers that a server sends back for access control requests as defined by the CORS specification.
Access-Control-Allow-Origin
The Access-Control-Allow-Origin
specifies either a single origin (or null), which tells browsers to allow that origin to access a resource. For requests without credentials - the '*'
wildcard, to tell browsers to allow any origin to access a resource.
If a server specifies a single origin rather than the '*'
wildcard, a server should also set Origin
in the Vary response header - to indicate to clients that server responses will differ based on the value of the Origin
request header.
Access-Control-Allow-Methods
The Access-Control-Allow-Methods
header specifies a method or methods allowed when accessing a resource. This is used in response to a preflight request.
Access-Control-Allow-Headers
The Access-Control-Allow-Headers
header is used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.
Access-Control-Expose-Headers
The Access-Control-Expose-Headers
header lets a server whitelist headers that browsers are allowed to access. By default, browsers have access to only the 7 CORS-safelisted response headers:
Cache-Control
Content-Language
Content-Length
Content-Type
Expires
Last-Modified
Pragma
Access-Control-Max-Age
The Access-Control-Max-Age
header indicates how long results of a preflight request can be cached.
Access-Control-Allow-Credentials
When a request's credentials mode (Request.credentials) is include
, browsers will only expose a response to frontend JavaScript code if the Access-Control-Allow-Credentials
value is true.
Credentials are cookies, authorization headers or TLS client certificates.
CORS misconfiguration
Abusing CORS without credentials
If a victim's network location works as a kind of authentication, you can use a victim’s browser as a proxy to bypass IP-based authentication and access applications within an internal network.
In terms of impact this is similar to DNS rebinding.
Breaking TLS with poorly configured CORS
Suppose an application that rigorously employs HTTPS also whitelists a trusted subdomain that is using plain HTTP. For instance, when an application receives the following request:
An application responds with:
In such case, an attacker who is in a position to intercept a victim's traffic can exploit the CORS configuration to compromise a victim's interaction with the application. The attack involves the next steps:
A victim user makes any plain HTTP request
An attacker injects a redirection to
http://trusted-subdomain.vulnerable-website.com
A victim's browser follows the redirect
An attacker intercepts the plain HTTP request, and returns a spoofed response containing a CORS request to
https://vulnerable-website.com
A victim's browser makes the CORS request, including the
http://trusted-subdomain.vulnerable-website.com
as an originAn application allows the request because the origin is whitelisted; requested sensitive data is returned in the response
An attacker's spoofed page can read the sensitive data and transmit it to any domain under their control
The attack is effective even if a vulnerable application is otherwise robust in its usage of HTTPS, with no HTTP endpoint and all cookies flagged as secure.
Broken parser
Most servers use basic string operations to verify the Origin
header, but some parse it as a URL instead. This allows you to exploit the browser's tolerance for unusual characters in domain names.
In Safari, https://website.com%60.attacker.com/
is a valid URL. If a CORS request originating from that URL, the Origin
header will look like next one:
A server may parse this header as https://website.com
omitting the `.attacker.com/
part.
Chrome and Firefox supported the _
character in subdomains, that can be used instead of `
to exploit Firefox and Chrome users.
You can also try to use other approaches to break a validation:
References:
Exploiting XSS via CORS trust relationships
Even "correctly" configured CORS establishes a trust relationship between two origins. If an application trusts an origin that is vulnerable to XSS, an attacker can inject JavaScript to retrieve sensitive information from the application using CORS.
Given the following request:
If an application responds with:
An attacker who finds an XSS vulnerability on subdomain.vulnerable-website.com
could use that to retrieve an API key using a URL like: https://subdomain.vulnerable-website.com/?xss=<script>cors-stuff-here</script>
Generation the Access-Control-Allow-Origin header
No browsers actually support a space-separated list of origins (the specification suggests this):
Additionally, a wildcard does not allow you to trust all subdomains:
There is only wildcard origin '*'
.
Since you can't use wildcard in Access-Control-Allow-Origin
when credentials flag is true, check Access-Control-Allow-Origin, many applications programmatically generate the Access-Control-Allow-Origin
header based on the user-supplied Origin
value. If you see a HTTP response with any Access-Control-*
headers but no origins declared, this is a strong indication that an application will generate the header based on a user input. Other applications will only send CORS headers if they receive a request containing the Origin
header, making associated vulnerabilities extremely easy to miss.
For instance, an application receives the following request:
and responds with:
If the response contains any sensitive information such as an API key or CSRF token, you can retrieve this by placing the following script on your resource:
Server-side cache poisoning
If an application reflects the Origin
header without even checking it for illegal characters like , you have a HTTP header injection vulnerability against IE/Edge users, because IE and Edge view \r (0x0d)
as a valid HTTP header terminator:
Internet Explorer sees the response as:
This is not directly exploitable because there is no way for an attacker to make someone's browser send such a malformed header, but you can manually craft this request and a server-side cache may save the response and serve it to other people. The current payload will change the page's character set to UTF-7, which is notoriously useful for creating XSS vulnerabilities.
The null origin
The specification for the Origin
header supports the value null
. Browsers might send the value null
in the Origin
header in various unusual situations:
Cross-site redirects
Requests from serialized data
Request using the
file:
protocolSandboxed cross-origin requests
Some applications might whitelist the null
origin to support local development of the application.
For instance, application receives the following request:
and responds with:
In such case, an attacker can use various tricks to generate a cross-domain request containing the value null
in the Origin
header. This will satisfy the whitelist, leading to cross-domain access. For example, this can be done using a sandboxed iframe cross-origin request of the form:
Vary: Origin and client-side cache poisoning
The CORS specification instructs developers specify Origin
in the Vary
response header whenever Access-Control-Allow-Origin
headers are dynamically generated.
That might sound pretty simple, but immense numbers of developers forget, including the W3C itself.
Suppose an application reflects the contents of a custom header without encoding (reflected XSS in a custom HTTP header):
Without CORS, this is impossible to exploit as there is no way to make someone's browser send the X-User-id
header cross-domain.
With CORS, you can make them send this request. By itself, that is useless since the response containing injected JavaScript will not be rendered. However, if Vary: Origin
has not been specified the response may be stored in the browser's cache and displayed directly when the browser navigates to the associated URL.
References
Last updated