Cross-Origin Resource Sharing (CORS)

Cross-Origin Resource Sharing (CORS) is a facility that allows a client to interact with resources from an origin that is different from where the first resource was obtained.

Usage

CORS is the process that allows a client to make HTTP requests from one server to another server. This is not normally allowed due to enforcement of the same-origin policy (SOP). The SOP is intended to prevent certain types of attacks, such as a malicious server running a script on a client’s browser that will allow them unauthorized access to local files.

An origin is the same if the host, port, and protocol are all the same. For example, if a server is using an HTTP Connection to serve a resource, then an HTTPS connection from the same server does not have the same origin. As such, the browser will not allow these types of HTTP requests unless they include the proper CORS headers.

Access to CORS functionality is accomplished using APIs such as XMLHttpRequest or Fetch, which both help to lower the risks associated with interacting with resources from multiple Origins. The CORS protocol essentially allows HTTP responses to include a direction stating that they are shareable with servers from different Origins.

Simple versus preflight requests

CORS requests are either simple or require an accompanying preflight request. A request preflight is a mechanism used to obtain permission in advance of sending the actual HTTP request.

If the CORS request is simple then a preflight request is not necessary. A simple HTTP request operates with several constraints that include, among other things, restrictions on the type of HTTP method, the HTTP headers it can include, and the type of content. For example, simple HTTP requests can only use the GET, HEAD, and POST methods.

For non-simple HTTP requests, the preflight will use special HTTP request headers to obtain permission and generally interact with the second server. Information about what is allowed will be returned using a special set of HTTP response headers.

CORS request headers

If an HTTP request includes the HTTP Origin header, it may be working inside of a CORS operation. A CORS preflight request verifies whether the protocol is supported. This is done by using the HTTP OPTIONS method that includes the HTTP request headers Access-Control-Request-Method and Access-Control-Request-Headers.

Note

Successful preflight requests will only return HTTP status code 200 OK or 204 No Content.

Access-Control-Request-Method

Access-Control-Request-Method indicates the HTTP method that a future HTTP request to the same resource might use.

Access-Control-Request-Headers

Access-Control-Request-Headers indicates the HTTP headers that a future HTTP request to the same resource might use.

CORS response headers

A CORS-supporting server can respond to such HTTP requests by including several HTTP headers.

Access-Control-Allow-Origin

Access-Control-Allow-Origin specifies the origin from which the server will accept CORS requests. Only one domain can be specified; however, a wildcard is permitted. The wildcard is an asterisk (*) allowing all domains, although this is a security risk and shall only be used for open or public systems. Values other than these will be rejected by the browser.

Access-Control-Allow-Credentials

If the value for Access-Control-Allow-Credentials is set to true, it means that the HTTP request can include credentials such as HTTP Cookies. When the HTTP header is not present, the default value is false. HTTP Cookies are not typically included in CORS requests to prevent CSRF attacks.

Access-Control-Expose-Headers

Access-Control-Expose-Headers specifies which non-default HTTP headers will be exposed to the client. CORS responses that include non-default and non-specified HTTP headers will still be successful, although the client will not expose them. A common example of a non-default HTTP header is Date. The default HTTP headers in a CORS response are Cache-Control, Expires, Last-Modified, Content-Type, Content-Language, and Pragma.

Access-Control-Max-Age

The Access-Control-Max-Age cache-control option specifies the number of seconds that the preflight request will be cached for.

Note

Some browsers have their own limit and specifying a higher one will not allow it to be exceeded.

Access-Control-Allow-Methods

Access-Control-Allow-Methods specifies the CORS request methods that are supported by the server. The server can return the asterisk (*) to state that all HTTP methods are allowed.

Access-Control-Allow-Headers

Access-Control-Allow-Headers specifies which headers are allowed by the CORS request. The server can return the asterisk (*) to state that all HTTP headers are allowed.

Requests with credentials

For a HTTP request that includes credentials, there are additional restrictions on the server due to security concerns. Wildcard access using the asterisk (*) is not allowed for Access-Control-Allow-Origin, Access-Control-Allow-Methods, or Access-Control-Allow-Headers.

Example

In this example, the client requests a resource from the origin. The HTTP request is successful but not fully complete, as the client needs to interact with resources accessible at database.example.re. This qualifies as a different origin. A preflight request is then made to see if CORS is supported for the HTTP POST method, where the intention is to send a textual XML file.

This preflight request includes the Origin HTTP request header, which specifies the first origin. Notice that the Origin header includes http://; this is mandatory because the protocol needs to match.

The Content-Type is important because POST is a simple HTTP request for certain types of content, and text/xml is not one of them.

The new server responds to state that it will accept CORS requests from the specified origin for several HTTP methods, including POST. Subsequent HTTP requests to the new origin will continue to include the Origin HTTP request header.

Initial request – first server

GET /clientlist.html HTTP/1.1
Host: www.example.re

Response from origin server

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 2500

<HTML document included in message body>

Preflight request

OPTIONS / HTTP/1.1
Host: database.example.re
Origin: http://www.example.re
Access-Control-Request-Method: POST
Access-Control-Request-Header: Content-Type

Response to preflight request

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.re
Access-Control-Allow-Methods: POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type
…

Subsequent request(s) for image(s) from new origin

POST /updateclient.xml HTTP/1.1
Host: database.example.re
Origin: http://www.example.re
Content-Type: text/xml

<Data for POST included in message body>

Takeaway

Cross-Origin Resource Sharing (CORS) is used to provide access to resources available at domains that are different from that of the original resource. HTTP requests can be simple or use an accompanying preflight request, where a preflight request is used to obtain permission in advance of making the original HTTP request. Not all servers support CORS, and many only support a subset of HTTP methods and HTTP headers. There are security concerns that need to be considered, such as whether sending credentials is allowed, when implementing CORS.

Last updated: August 8, 2023