small rephrasings
This commit is contained in:
parent
2b79ab1ff8
commit
7a7b25a943
1 changed files with 25 additions and 25 deletions
|
@ -28,7 +28,7 @@ Seriously. Let's make a very brief historical digression.
|
|||
|
||||
**For many years a script from one site could not access the content of another site.**
|
||||
|
||||
That simple, yet powerful rule was a foundation of the internet security. E.g. an evil script from website `hacker.com` could not access user's mailbox at website `gmail.com`. People felt safe.
|
||||
That simple, yet powerful rule was a foundation of the internet security. E.g. an evil script from website `hacker.com` could not access the user's mailbox at website `gmail.com`. People felt safe.
|
||||
|
||||
JavaScript also did not have any special methods to perform network requests at that time. It was a toy language to decorate a web page.
|
||||
|
||||
|
@ -125,15 +125,15 @@ Contrary to that, requests with non-standard headers or e.g. method `DELETE` can
|
|||
|
||||
When we try to make a unsafe request, the browser sends a special "preflight" request that asks the server -- does it agree to accept such cross-origin requests, or not?
|
||||
|
||||
And, unless the server explicitly confirms that with headers, a unsafe request is not sent.
|
||||
And, unless the server explicitly confirms that with headers, an unsafe request is not sent.
|
||||
|
||||
Now we'll go into details.
|
||||
|
||||
## CORS for safe requests
|
||||
|
||||
If a request is cross-origin, the browser always adds `Origin` header to it.
|
||||
If a request is cross-origin, the browser always adds the `Origin` header to it.
|
||||
|
||||
For instance, if we request `https://anywhere.com/request` from `https://javascript.info/page`, the headers will be like:
|
||||
For instance, if we request `https://anywhere.com/request` from `https://javascript.info/page`, the headers will look like:
|
||||
|
||||
```http
|
||||
GET /request
|
||||
|
@ -144,9 +144,9 @@ Origin: https://javascript.info
|
|||
...
|
||||
```
|
||||
|
||||
As you can see, `Origin` header contains exactly the origin (domain/protocol/port), without a path.
|
||||
As you can see, the `Origin` header contains exactly the origin (domain/protocol/port), without a path.
|
||||
|
||||
The server can inspect the `Origin` and, if it agrees to accept such a request, adds a special header `Access-Control-Allow-Origin` to the response. That header should contain the allowed origin (in our case `https://javascript.info`), or a star `*`. Then the response is successful, otherwise an error.
|
||||
The server can inspect the `Origin` and, if it agrees to accept such a request, add a special header `Access-Control-Allow-Origin` to the response. That header should contain the allowed origin (in our case `https://javascript.info`), or a star `*`. Then the response is successful, otherwise it's an error.
|
||||
|
||||
The browser plays the role of a trusted mediator here:
|
||||
1. It ensures that the correct `Origin` is sent with a cross-origin request.
|
||||
|
@ -182,7 +182,7 @@ There's no `Content-Length` header in the list!
|
|||
This header contains the full response length. So, if we're downloading something and would like to track the percentage of progress, then an additional permission is required to access that header (see below).
|
||||
```
|
||||
|
||||
To grant JavaScript access to any other response header, the server must send `Access-Control-Expose-Headers` header. It contains a comma-separated list of unsafe header names that should be made accessible.
|
||||
To grant JavaScript access to any other response header, the server must send the `Access-Control-Expose-Headers` header. It contains a comma-separated list of unsafe header names that should be made accessible.
|
||||
|
||||
For example:
|
||||
|
||||
|
@ -197,7 +197,7 @@ Access-Control-Expose-Headers: Content-Length,API-Key
|
|||
*/!*
|
||||
```
|
||||
|
||||
With such `Access-Control-Expose-Headers` header, the script is allowed to read `Content-Length` and `API-Key` headers of the response.
|
||||
With such an `Access-Control-Expose-Headers` header, the script is allowed to read the `Content-Length` and `API-Key` headers of the response.
|
||||
|
||||
## "Unsafe" requests
|
||||
|
||||
|
@ -205,9 +205,9 @@ We can use any HTTP-method: not just `GET/POST`, but also `PATCH`, `DELETE` and
|
|||
|
||||
Some time ago no one could even imagine that a webpage could make such requests. So there may still exist webservices that treat a non-standard method as a signal: "That's not a browser". They can take it into account when checking access rights.
|
||||
|
||||
So, to avoid misunderstandings, any "unsafe" request -- that couldn't be done in the old times, the browser does not make such requests right away. Before it sends a preliminary, so-called "preflight" request, asking for permission.
|
||||
So, to avoid misunderstandings, any "unsafe" request -- that couldn't be done in the old times, the browser does not make such requests right away. First, it sends a preliminary, so-called "preflight" request, to ask for permission.
|
||||
|
||||
A preflight request uses method `OPTIONS`, no body and two headers:
|
||||
A preflight request uses the method `OPTIONS`, no body and two headers:
|
||||
|
||||
- `Access-Control-Request-Method` header has the method of the unsafe request.
|
||||
- `Access-Control-Request-Headers` header provides a comma-separated list of its unsafe HTTP-headers.
|
||||
|
@ -221,7 +221,7 @@ If the server agrees to serve the requests, then it should respond with empty bo
|
|||
|
||||

|
||||
|
||||
Let's see how it works step-by-step on example, for a cross-origin `PATCH` request (this method is often used to update data):
|
||||
Let's see how it works step-by-step on the example of a cross-origin `PATCH` request (this method is often used to update data):
|
||||
|
||||
```js
|
||||
let response = await fetch('https://site.com/service.json', {
|
||||
|
@ -240,7 +240,7 @@ There are three reasons why the request is unsafe (one is enough):
|
|||
|
||||
### Step 1 (preflight request)
|
||||
|
||||
Prior to sending such request, the browser, on its own, sends a preflight request that looks like this:
|
||||
Prior to sending such a request, the browser, on its own, sends a preflight request that looks like this:
|
||||
|
||||
```http
|
||||
OPTIONS /service.json
|
||||
|
@ -259,14 +259,14 @@ Access-Control-Request-Headers: Content-Type,API-Key
|
|||
|
||||
### Step 2 (preflight response)
|
||||
|
||||
The server should respond with status 200 and headers:
|
||||
The server should respond with status 200 and the headers:
|
||||
- `Access-Control-Allow-Origin: https://javascript.info`
|
||||
- `Access-Control-Allow-Methods: PATCH`
|
||||
- `Access-Control-Allow-Headers: Content-Type,API-Key`.
|
||||
|
||||
That allows future communication, otherwise an error is triggered.
|
||||
|
||||
If the server expects other methods and headers in the future, it makes sense to allow them in advance by adding to the list.
|
||||
If the server expects other methods and headers in the future, it makes sense to allow them in advance by adding them to the list.
|
||||
|
||||
For example, this response also allows `PUT`, `DELETE` and additional headers:
|
||||
|
||||
|
@ -280,13 +280,13 @@ Access-Control-Max-Age: 86400
|
|||
|
||||
Now the browser can see that `PATCH` is in `Access-Control-Allow-Methods` and `Content-Type,API-Key` are in the list `Access-Control-Allow-Headers`, so it sends out the main request.
|
||||
|
||||
If there's header `Access-Control-Max-Age` with a number of seconds, then the preflight permissions are cached for the given time. The response above will be cached for 86400 seconds (one day). Within this timeframe, subsequent requests will not cause a preflight. Assuming that they fit the cached allowances, they will be sent directly.
|
||||
If there's the header `Access-Control-Max-Age` with a number of seconds, then the preflight permissions are cached for the given time. The response above will be cached for 86400 seconds (one day). Within this timeframe, subsequent requests will not cause a preflight. Assuming that they fit the cached permissions. They will be sent directly.
|
||||
|
||||
### Step 3 (actual request)
|
||||
|
||||
When the preflight is successful, the browser now makes the main request. The algorithm here is the same as for safe requests.
|
||||
When the preflight is successful, the browser now makes the main request. The process here is the same as for safe requests.
|
||||
|
||||
The main request has `Origin` header (because it's cross-origin):
|
||||
The main request has the `Origin` header (because it's cross-origin):
|
||||
|
||||
```http
|
||||
PATCH /service.json
|
||||
|
@ -316,7 +316,7 @@ JavaScript only gets the response to the main request or an error if there's no
|
|||
|
||||
A cross-origin request initiated by JavaScript code by default does not bring any credentials (cookies or HTTP authentication).
|
||||
|
||||
That's uncommon for HTTP-requests. Usually, a request to `http://site.com` is accompanied by all cookies from that domain. But cross-origin requests made by JavaScript methods are an exception.
|
||||
That's uncommon for HTTP-requests. Usually, a request to `http://site.com` is accompanied by all cookies from that domain. Cross-origin requests made by JavaScript methods on the other hand are an exception.
|
||||
|
||||
For example, `fetch('http://another.com')` does not send any cookies, even those (!) that belong to `another.com` domain.
|
||||
|
||||
|
@ -362,12 +362,12 @@ From the browser point of view, there are two kinds of cross-origin requests: "s
|
|||
|
||||
The essential difference is that safe requests were doable since ancient times using `<form>` or `<script>` tags, while unsafe were impossible for browsers for a long time.
|
||||
|
||||
So, the practical difference is that safe requests are sent right away, with `Origin` header, while for the other ones the browser makes a preliminary "preflight" request, asking for permission.
|
||||
So, the practical difference is that safe requests are sent right away, with the `Origin` header, while for the other ones the browser makes a preliminary "preflight" request, asking for permission.
|
||||
|
||||
**For safe requests:**
|
||||
|
||||
- → The browser sends `Origin` header with the origin.
|
||||
- ← For requests without credentials (not sent default), the server should set:
|
||||
- → The browser sends the `Origin` header with the origin.
|
||||
- ← For requests without credentials (not sent by default), the server should set:
|
||||
- `Access-Control-Allow-Origin` to `*` or same value as `Origin`
|
||||
- ← For requests with credentials, the server should set:
|
||||
- `Access-Control-Allow-Origin` to same value as `Origin`
|
||||
|
@ -377,11 +377,11 @@ Additionally, to grant JavaScript access to any response headers except `Cache-C
|
|||
|
||||
**For unsafe requests, a preliminary "preflight" request is issued before the requested one:**
|
||||
|
||||
- → The browser sends `OPTIONS` request to the same URL, with headers:
|
||||
- → The browser sends an `OPTIONS` request to the same URL, with the headers:
|
||||
- `Access-Control-Request-Method` has requested method.
|
||||
- `Access-Control-Request-Headers` lists unsafe requested headers.
|
||||
- ← The server should respond with status 200 and headers:
|
||||
- ← The server should respond with status 200 and the headers:
|
||||
- `Access-Control-Allow-Methods` with a list of allowed methods,
|
||||
- `Access-Control-Allow-Headers` with a list of allowed headers,
|
||||
- `Access-Control-Max-Age` with a number of seconds to cache permissions.
|
||||
- Then the actual request is sent, the previous "safe" scheme is applied.
|
||||
- `Access-Control-Max-Age` with a number of seconds to cache the permissions.
|
||||
- Then the actual request is sent and the previous "safe" scheme is applied.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue