Cross-Origin Resource Sharing or CORS is a mechanism that enables a web browser to perform “cross-domain” requests. Cross-domain requests are HTTP requests for resources hosted on a different domain than the domain of the resource making the request. CORS is a W3 Spec supported in HTML5 that manages XMLHttpRequest access to a different domain. It provides a set of request and response headers for defining which domains can access data and which HTTP methods they can utilize.But first, let us understand what is same origin policy and its associated challenges.
If a server wants its resources to be available securely to other domains it should use the below headers to control access to it resources
- Access-Control-Allow-Methods : This header indicates the methods that can be used on the resource from other domains. The acceptable values are the HTTP verbs POST, PUT, GET, etc
- Access-Control-Allow-Headers: This indicates a comma-separated list of headers accepted by the server providing the resource.
- Access-Control-Allow-Credentials: This is an optional header and if set to true indicates that the server allows cookies (or other user credentials) to be included on cross-origin requests.
- Access-Control-Expose-Headers : This is an optional header and provides explicit permission to the client to read response headers. This is primarily for compatibility with pre-CORS clients. This header is used in CORS preflight requests. It indicates how long the results of a preflight request can be cached. The results of this preflight request are the headers defined above primarily the Access-Control-Allow-Methods and Access-Control-Allow-Headers.
A client uses the below request headers to initiate a CORS request
- Origin : This defines where the actual request originates from.
- Access-Control-Request-Method: This defines the method used in the request.
- Access-Control-Request-Header: This defines the headers used in the request.
CORS also differs between a simple and a “non-simple” request. If a client makes a non-simple request then it results in two HTTP calls to access the resource.The first call is an OPTIONS pre-flight request which determines if the second call should be issued. The first preflight response indicates if the server allows the necessary headers and methods in the Access-Control-Allow-Headers and Access-Control-Allow-Methods response headers. The second call is the actual request and is dependent on the success of the preflight response.
An HTTP request is classified as a “non- Simple” request if
- It uses an HTTP verb other than a GET or POST (PUT, DELETE, PATCH )
- It uses any request headers other than Accept, Accept-Language, Content-Language and a Content-Type of application/x-www-form-urlencoded, multipart/form-data, or text/plain.
A general preflight request header is as shown below.
A valid CORS request always contains an Origin header. This Origin header is added by the browser, and cannot be controlled by the user. The value of this header is the scheme (e.g. HTTP), domain (e.g. mydomain.com) and port (included only if it is not a default port, e.g. 8080) from which the request originates. In response, the server sends back an Access-Control-Allow-Origin header as shown below
date:"Sat, 17 Feb 2018 14:07:48 GMT"
In this case, the server responds with a Access-Control-Allow-Origin: * which means that the resource can be accessed by any domain in a cross-site manner. If the resource owners at /api/testapi wished to restrict access to the resource to requests only from http://alloweddomain.org, they would send back:
Note that now, no domain other than http://alloweddomain.org (identified by the ORIGIN: header in the request) can get access to the resource in a cross-site manner. The Access-Control-Allow-Origin header should contain the value that was sent in the request’s Origin header.
In Asp.net core CORS functionality for the pipeline is defined in the package Microsoft.AspNetCore.MVC.Cors. It can be included in the pipeline by adding cors in the startup class as below
In the above startup class, I am adding CORS into the pipeline by calling Service.AddCors and defining a policy. The policy specified is a very liberal policy allowing all headers, origins, and methods. I am then configuring the service by calling app.UseCors() and specifying the policy defined above. I will look at defining CORS policies in detail in a further post.