Cross-Origin Resource Sharing (CORS)

Before sending the actual cross-origin request, the browser makes a preflight request to the intended destination using the OPTIONS HTTP method to determine if the requesting domain may perform the requested action. E.g.:

OPTIONS /foo HTTP/1.1
Host: hostname.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://domain.com                  - domain initiating the request
Access-Control-Request-Method: POST        - what method the browser will include in the request
Access-Control-Request-Headers: X-UserId   - what headers the browser will include in the request

Some cross-origin requests do not trigger a preflight request. These are known as simple requests which include standard GET, HEAD, and POST requests. However, other request methods, requests with custom HTTP headers, or POST requests with nonstandard content-types will require a preflight request.

Play with Origin header to bypass the allow list:

curl -X "OPTIONS" -i -H "Origin: http://fake<domain>.com" -k https://<url>/allowlist

Responses

Servers can set several headers to enable CORS. Let's review the most commonly encountered ones.

HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Wed, 23 Jun 2021 17:38:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Connection: close
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: https://domain.com - indicates which origins are allowed
Access-Control-Allow-Credentials: true    - indicates if the browser should include creds such a cookies or authorization headers
Access-Control-Allow-Headers: X-UserId

The Access-Control-Allow-Origin header indicates which origins are allowed to access resources from the server. A wildcard value (*) used in this header indicates any origin can access the resource. Generally, servers should only use this setting for resources that are considered publicly accessible. The header can also specify a single origin. If an application needs to allow multiple origins to access it, the application must contain logic to respond with the appropriate domain.

The Access-Control-Allow-Credentials header indicates if the browser should include credentials, such as cookies or authorization headers. The only valid value for this header is "true". Instead of setting a "false" value, servers can simply omit the header. A web application must set a non-wildcard value in the Access-Control-Allow-Origin header if it wishes to set Access-Control-Allow-Credentials to "true". However, the browser will enforce the SameSite attribute on any cookies that it would send cross-origin regardless of the destination's CORS settings. In other words, if the cookie has SameSite=Lax, the browser will not send it even if the preflight request indicates that the destination server allows credentials on CORS requests.

The Access-Control-Allow-Methods header indicates which HTTP methods cross-origin requests may use. The header value can contain one or more methods in a comma-separated list.

Similarly, the Access-Control-Allow-Headers header indicates which HTTP headers may be used on a cross-origin request. The header value can contain one or more header names in a comma-separated list. Browsers will consider some headers safe, such as Content-Type, and therefore, always use them in cross-origin requests. However, servers must use the Access-Control-Allow-Headers header to allow the authorization header or custom headers on CORS requests.

Important

Access-Control-Allow-Origin : * does not allow Access-Control-Allow-Credentials to be set to true (Access-Control-Allow-Credentials : true), which means that there must be a custom solutions for handling multiple origin values.

Same-Origin Policy (SOP)

SOP does not prevent the request from being sent, but instead prevents the response from being read by the JavaScript.

However, there are exceptions. Some requests require an HTTP preflight request (sent with the OPTIONS method), which determines if the subsequent browser request should be allowed to be sent.

Standard GET, HEAD, and POST requests don't require preflight requests. However, other request methods, requests with custom HTTP headers, or POST requests with nonstandard content-types will require a preflight request.

URLRESULTREASON
https://a.com/myInfoAllowedSame Origin
http://a.com/users.jsonBlockedDifferent Scheme and Port
https://api.a.com/infoBlockedDifferent Domain
https://a.com**:8443**/filesBlockedDifferent Port
https://b.com/analyticsBlockedDifferent Domain