CORS definition
Before defining CORS, some fundamental concepts to understand CORS will be defined.
origin
Given a URL, the origin is the first part that is made up of the scheme: the host and the port (if present).
source = scheme + host + port
For example, in https://localhost:8080/surveys
the source is https://localhost:8080
and /survey
is the path
same-origin
It refers to the case where the client makes a request to a server and the server has the same origin as the client.
https://aurora.net/home -> https://aurora.net/api/pos?id=290
cross-origin (cross-origin)
The client makes a request to a server whose origin is different from that of the client.
https://localhost:8080/home -> https://aurora.net/api/pos?id=290
https://localhost:8080/home -> https://127.0.0.1:8080/api/pos?id=290
https://localhost:8080/home -> https://127.0.0.1:3000/api/pos?id=290
Same-origin policy and CORS
By default and by security policy, browsers only allow HTTP requests to the same origin, that is, to the same domain as the page that makes the request.
CORS (Cross-Origin Resource Sharing) is the mechanism by which browsers allow a request to be made from one origin to a different one, cross-origin.
In order to make a CORS request, the client does not have to do anything, it simply launches the request. The browser makes the request and it is the server that must respond if it accepts requests from that origin. It does this by sending the Access-Control-Allow-Origin
header response. This header can have an asterisk (*
) or a specific origin. The *
means that the server accepts requests from any origin.
The browser reviews the browser's response. If you have the Access-Control-Allow-Origin
header and it has the value *
or the origin matches the client origin, then the browser accepts the response. Otherwise, it discards it and generally displays a CORS-descriptive error on the console.
1. browser with origin X makes a request to origin Y
2. server responds
3. If the response from the server includes the header `Access-Control-Allow-Origin` Then
4. If (Access-Control-Allow-Origin == '*') or (Access-Control-Allow-Origin == X) Then
5. browser accepts the response
6. If not
7. discard response and show error
8. End Yes
9. If not
10. discard response and show error
11. End Yes
Access-Control-Allow-Origin
can also be set tonull
for unknown origins (such as accessing from a file instead of a website). This is useful while you are in a development or testing phase, this way you don't need to put '*' which is less restrictive.Access-Control-Allow-Origin: null
Preflight
Above we have seen in a generic way how a cross-origin request should be treated using CORS. Actually, before making a cross-origin request, browsers that implement CORS will "meta" the actual request.
A preflight is a request that the browser makes before making a CORS request if the request meets one of these criteria:
- Use an HTTP method other than
GET
,POST
, orHEAD
- Set the
Content-Type
header to a value other than: -application/x-www-form-urlencoded- multipart/form-data -text/plain
- Set additional headers other than:
-
Accept
Accept-Language
Content-Language
- The XMLHttpRequest object contains upload events
The HTTP methods
GET
,POST
andHEAD
are called simple methods. Simple methods do not need to be listed in theControl-Allow-Methods
header.
The preflight is a request with the OPTIONS
HTTP method. This "meta" request that the browser makes is for the server to decide how to respond to CORS. In the preflight the browser sends the headers:
Origin
-
Access-Control-Request-Method
(supports only one method) -
Access-Control-Request-Headers
(only if the headers are not simple. You can have a comma-separated list of headers)
The server checks if the HTTP origin and method are in its list of allowed origins and methods (it will also check the headers indicated in Access-Control-Request-Headers
, if any). If this check is favorable, it responds with a status code in the range 200
. The answer should not wear a bodysuit. The headers sent by the server are:
Access-Control-Allow-Origin
-
Access-Control-Allow-Methods
(in this case it can be a comma separated list of commands) Access-Control-Allow-Headers
Example of preflight request:
OPTIONS /api/posts HTTP/1.1
User-Agent: Chrome
Host: 127.0.0.1:8080
Accept: */*
Origin: http://localhost:3000
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Security-Level, App-Name
Example preflight response:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http//localhost:3000
Access-Control-Allow-Methods: GET, DELETE
Access-Control-Allow-Headers: Security-Level, App-Name
Request example:
GET /api/posts HTTP/1.1
User-Agent: Chrome
Host: 127.0.0.1:8080
Accept: */*
Origin: http://localhost:3000
Security-Level: High
App-Name: Survey
The previous algorithm, now modified with the preflights, would look like this:
1. the Javascript client whose origin is X, makes a request P to the server with origin Y.
P contains the HTTP method M and a set of headers C
2. If M is a simple HTTP method and all C headers are simple Then
3. send the request P to the server
4. If not
5. prepare a preflight request F with HTTP OPTIONS method and a set of headers C' with:
Origin = X, Access-Control-Request-Method = M
6. If in C there are headers that are not simple Then
7. add to C' the Access-Control-Request-Headers header with the list of non-simple C headers
8. End Yes
9. send preflight F to server
10 If server responds to preflight with status in the range of 200 Then
11. send the request P to the server
12. If not
13. Check the Access-Control-Allow-Origin response headers,
Access-Control-Allow-Methods and Access-Control-Allow-Headers to determine which
are the validations that have failed and report the error
14. End Yes
15. End Yes
Cache. The browser can cache the preflights and thus avoid making an extra request for each client request that would require a preflight. The cache saves on its origin + path entries.
Canvas and images
For images whose src
attribute is a different origin than the client, the browser loads the resource and displays it but does not allow manipulations with it such as toBlob
, toDataURL
, and getImageData
.
To enable CORS in the case of images, there is the crossOrigin
attribute that can take the values anonymous
or user-credentials
. user-credentials
is like withCredentials
in XMLHttpRequest, ie user credentials (eg cookies) are sent with the request. If it is not necessary to send the credentials, it is preferable to send anonymous
.
Cookies and user credentials
By default the browser does not send user credentials as cookies in cross-origin requests. The browser also does not expose all the response headers that the server sends.
That's why CORS has mechanisms to remedy those restrictions: the Access-Control-Allow-Credentials
and Access-Control-Expose-Headers
response headers.
So for the use of cookies it is necessary for the client to indicate:
xhr.withCredentials = true;
document.cookie = someUniqueId;
The server must respond to the preflight and the request with the headers
Access-Control-Allow-Credentials
and Access-Control-Allow-Origin
.
When the server sends the Access-Control-Allow-Credentials
header with the value true
, it must send the Access-Control-Allow-Origin
header with a specific origin; Access-Control-Allow-Origin: *
is invalid because accepting cookies from any origin can cause security problems.
Valid:
Access-Control-Allow-Origin: http://localhost:1111
Access-Control-Allow-Credentials: true
Invalid:
Access-Control-Allow-Origin: \*
Access-Control-Allow-Credentials: true
In the case where the client has xhr.withCredentials = true
and the server responds with Access-Control-Allow-Origin: true
, the server can set cookies on the client. These cookies will be sent by the browser in successive requests, however, the client will not be able to read these cookies with Javascript.
Response headers
The XMLHttpRequest object exposes two methods for reading response headers: getResponseHeader
and getAllResponseHeaders
. In a same-origin request these methods return all the headers sent by the server. When dealing with a cross-origin request, only the plain headers can be read.
Using the Access-Control-Expose-Headers
header the server can specify which headers the client can read.
Access-Control-Expose-Headers: X-Powered-By
Simple headers:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Summary of headers used in CORS
Request headers (sent by client browser)
-
Origin
: Header added by the browser. Contains the origin of the client in the request. Counterpart:Access-Control-Allow-Origin
. -
Access-Control-Request-Method
: Header added by the browser in the preflight. Contains the HTTP method that the client will do on the actual request. Counterpart:Access-Control-Allow-Methods
. -
Access-Control-Request-Headers
: Header added by the browser in the preflight. Contains the HTTP headers that the client will send in the actual request. Counterpart:Access-Control-Allow-Headers
.
Response headers (sent by the server)
Access-Control-Allow-Origin
: The value*
indicates that all origins are allowed
A specific value indicates that the server only accepts requests from that source
The valuenull
indicates that it only accepts requests from sources that are not a web site, for example a file (only recommended for development and testing). Counterpart:Origin
Access-Control-Allow-Credentials
: The valuetrue
indicates that the server supports the use of user credentials such as cookies.Access-Control-Allow-Methods
: Has a list of HTTP methods accepted by the server.
It is not necessary to include the simple methods, although it is good practice to do so.
This header should only be sent in response to preflight requests. Counterpart:Access-Control-Request-Methods
Access-Control-Allow-Headers
: Has a list of HTTP headers accepted by the server.
This header should only be sent in response to preflight requests. Counterpart:Access-Control-Request-Headers
Access-Control-Max-Age
: Its value specifies the maximum time in seconds that it is recommended to keep a preflight cache, although the browser can have its own maximum value.
This header should only be sent in response to preflight requests.Access-Control-Expose-Headers
: Contains the headers that can be read by the browser. You can have a comma separated list of headers.
It is optional and is not required for the CORS request to be successful.
Top comments (0)