Author: valentinog
Translator: Front-end Xiaozhi Source: valentinog
If you have dreams and dry goods, you can search for [Great Relocation to the World] on WeChat and pay attention to this Shuwanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
What are cookies in web development?
A cookie is a small piece of data that the backend can store in the user's browser. The most common use cases for cookies include user tracking, personalization, and authentication.
Cookies have many privacy concerns and have been heavily regulated over the years.
In this article, focus on the technical aspects: learning how to create, use HTTP cookies on the front-end and back-end.
Backend configuration
The backend example is written in Flask . If you want to follow along, you can create a new Python virtual environment, move into it and install Flask
mkdir cookies && cd $_
python3 -m venv venv
source venv/bin/activate
pip install Flask
Create a new file named 为flask app.py
in the project folder and experiment locally using the examples in this article.
Who creates cookies?
First, where do cookies come from? who creates cookies?
While it is possible to use document.cookie
to create a cookie in the browser, in most cases it is the backend's responsibility to set the cookie in the request before it will respond to the client request.
Backend means that cookies can be created in the following ways:
- Code for the actual application on the backend (Python, JavaScript, PHP, Java)
- A web server (Nginx, Apache) that responds to requests
Backends can set cookies in HTTP requests with the Set-Cookie attribute, which is a corresponding string consisting of key/value pairs and optional attributes:
Set-Cookie: myfirstcookie=somecookievalue
When do you need to create a cookie? It depends on demand.
Cookies are simple strings. Create a Python file named flask_app.py
in the project folder and enter the following:
from flask import Flask, make_response
app = Flask(__name__)
@app.route("/index/", methods=["GET"])
def index():
response = make_response("Here, take some cookie!")
response.headers["Set-Cookie"] = "myfirstcookie=somecookievalue"
return response
Then run the application:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
When the app runs, the user accesses http://127.0.0.1:5000/index/
and the backend will set a response header named Set-Cookie
with a key/value pair.
( 127.0.0.1:5000
is the default listening address/port for developing Flask applications).
Set-Cookie
header is the key to understanding how cookies are created:
response.headers["Set-Cookie"] = "myfirstcookie=somecookievalue"
Most frameworks have their own way of setting cookies, such as Flask's set_cookie()
.
How to view cookies?
After visiting http://127.0.0.1:5000/index/
, the backend will set a cookie in the browser. To view this cookie, call document.cookie
from the browser's console:
Or you can check the Storage
tab in the developer tools. Click on the cookie, you will see the specific content of the cookie:
On the command line, you can also use curl
to see which cookies are set by the backend
curl -I http://127.0.0.1:5000/index/
Cookies can be saved to a file for later use:
curl -I http://127.0.0.1:5000/index/ --cookie-jar mycookies
Display cookies on stdout:
curl -I http://127.0.0.1:5000/index/ --cookie-jar -
Please note that there is no HttpOnly
attribute of cookie
, in the browser you can use the document.cookie
HttpOnly
attribute to access, if set ---5dc519be66ecc32cec59be665-cc32cec59be65 document.cookie
cc32aa document.cookie
can't read it.
Set-Cookie: myfirstcookie=somecookievalue; HttpOnly
Now, the cookie will still appear in the Storage
tab, but document.cookie
return an empty string.
From now on, cookies are created on the backend using Flask's response.set_cookie()
for convenience.
I have a cookie, what do I do now?
Your browser gets a cookie. Now what? Once you have the cookie, the browser can send the cookie back to the backend.
This has many uses such as: user tracking, personalization, and most importantly, authentication.
For example, once you log into the site, the backend will give you a cookie:
Set-Cookie: userid=sup3r4n0m-us3r-1d3nt1f13r
In order to correctly identify us in each subsequent request, the backend checks the cookie from the browser in the request
To send a cookie, the browser appends a Cookie
header to the request:
Cookie: userid=sup3r4n0m-us3r-1d3nt1f13r
Cookies can be set to expire: Max-Age and expires
By default, cookies expire when the user closes the session, that is, when the browser is closed. To persist cookies, we can pass the expires
or Max-Age
attribute
Set-Cookie: myfirstcookie=somecookievalue; expires=Tue, 09 Jun 2020 15:46:52 GMT; Max-Age=1209600
Note: Max-Age takes precedence over expires .
The scope of the cookie is the website path: the path attribute
Consider this backend, which sets a new cookie for its frontend when visiting http://127.0.0.1:5000/
. Instead, on the other two paths, we print the requested cookie
:
from flask import Flask, make_response, request
app = Flask(__name__)
@app.route("/", methods=["GET"])
def index():
response = make_response("Here, take some cookie!")
response.set_cookie(key="id", value="3db4adj3d", path="/about/")
return response
@app.route("/about/", methods=["GET"])
def about():
print(request.cookies)
return "Hello world!"
@app.route("/contact/", methods=["GET"])
def contact():
print(request.cookies)
return "Hello world!"
Run the application:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
In another terminal, if we make a connection to the root route, we can see the cookie in 在Set-Cookie
:
curl -I http://127.0.0.1:5000/ --cookie-jar cookies
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 23
Set-Cookie: id=3db4adj3d; Path=/about/
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 27 May 2020 09:21:37 GMT
Note that at this point the cookie has Path
attribute:
Set-Cookie: id=3db4adj3d; Path=/about/
/about/
Route and save cookies
curl -I http://127.0.0.1:5000/about/ --cookie cookies
Run the following command in the terminal of the Flask application, you can see:
ImmutableMultiDict([('id', '3db4adj3d')])
127.0.0.1 - - [27/May/2020 11:27:55] "HEAD /about/ HTTP/1.1" 200 -
As expected, the cookie is returned to the backend. Now try to access /contact/
route:
url -I http://127.0.0.1:5000/contact/ --cookie cookies
Run the following command in the terminal of the Flask application, you can see:
ImmutableMultiDict([])
127.0.0.1 - - [27/May/2020 11:29:00] "HEAD /contact/ HTTP/1.1" 200 -
What does this mean? The scope of the cookie is Path
. A cookie with a given path attribute cannot be sent to another unrelated path, even if the two paths are in the same domain.
This is the first layer of cookie permissions.
When Path
is omitted during cookie creation, the browser defaults to /
.
The scope of the cookie is the domain name: the domain attribute
The value of the cookie's Domain
attribute controls whether the browser should accept cookies and where the cookie is returned.
Let's look at some examples.
Everyone said that there is no project to write on the resume, so I helped you find a project, and also included a [Building Tutorial] .
host mismatch (wrong host)
View the cookies set by https://serene-bastion-01422.herokuapp.com/get-wrong-domain-cookie/
:
Set-Cookie: coookiename=wr0ng-d0m41n-c00k13; Domain=api.valentinog.com
Here the cookie is from serene-bastion-01422.herokuapp.com , but the Domain
attribute has api.valentinog.com .
Browsers have no other option to refuse this cookie. For example Chrome will give a warning (Firefox does not)
Host mismatch (subdomain)
View the cookies set by https://serene-bastion-01422.herokuapp.com/get-wrong-subdomain-cookie/
:
Set-Cookie: coookiename=wr0ng-subd0m41n-c00k13; Domain=secure-brushlands-44802.herokuapp.com
The cookie here is from serene-bastion-01422.herokuapp.com
, but the "Domain" attribute is secure-brushlands-44802.herokuapp.com
.
They are on the same domain, but the subdomains are different. Likewise, browsers also reject this cookie:
host match (entire domain)
View the cookies set by https://www.valentinog.com/get-domain-cookie.html
:
set-cookie: cookiename=d0m41n-c00k13; Domain=valentinog.com
This cookie is set on the web server using Nginx add_header:
add_header Set-Cookie "cookiename=d0m41n-c00k13; Domain=valentinog.com";
There are various ways of setting cookies in Nginx used here. Cookies are set by the code of the web server or application and are irrelevant to the browser.
What matters is which domain the cookie comes from.
The browser will happily accept cookies here, because the host in Domain
includes the host the cookie came from.
In other words, valentinog.com
includes the subdomain www.valentinog.com
.
At the same time, new requests for 对valentinog.com
will carry the cookie, as well as any requests to the valentinog.com
subdomain.
Here's a www
subdomain request with a cookie attached:
Below is a request to another subdomain that automatically appends cookies
List of Cookies and Public Suffixes
View the cookies set by https://serene-bastion-01422.herokuapp.com/get-domain-cookie/:
:
Set-Cookie: coookiename=d0m41n-c00k13; Domain=herokuapp.com
Here the cookie from serene-bas-01422.herokuapp.com
, Domain
attribute is herokuapp.com
. what the browser should do here
You might think that serene-base-01422.herokuapp.com
is contained in the herokuapp.com
domain, so the browser should accept cookies.
Instead, it rejects the cookie because it is from a domain included in the public suffix list .
Public Suffix List. This list lists top-level domains and domains that are open for registration. Browsers prevent domains on this list from being written to cookies by subdomains.
host match (subdomain)
View the cookies set by https://serene-bastion-01422.herokuapp.com/get-subdomain-cookie/:
:
Set-Cookie: coookiename=subd0m41n-c00k13
When the domain is omitted during cookie creation, the browser defaults to showing the origin host in the address bar, in this case my code does this:
response.set_cookie(key="coookiename", value="subd0m41n-c00k13")
When the cookie goes into the browser's cookie store, we see that Domain
is applied:
Now, we have the cookie from serene-bastion-01422.herokuapp.com
, where should the cookie go now?
If you visit https://serene-bastion-01422.herokuapp.com/
, the cookie comes with the request:
However, if you visit herokuapp.com
, the cookie does not appear with the request:
In a nutshell, browsers use the following heuristics to decide what to do with cookies (where sender host refers to the actual URL you visit):
- Completely reject cookies if the domain or subdomain in "Domain" does not match the visited host
- Reject the cookie if the value of
Domain
is included in the public suffix list - If the domain or subdomain in
Domain
matches the visited host, accept the cookie
Once the browser accepts the cookie, and is about to make a request, it says:
- If the requesting host exactly matches the value I see in
Domain
the cookie will just be returned - If the requesting host is a subdomain that exactly matches the value I see in "Domain", the cookie will be passed back
- If the requesting host is a subdomain like
sub.example.dev
example.dev
, a cookie will be returned - If the requesting host is a primary domain such as
example.dev
and the Domain is such assub.example.dev
, no cookie will be returned.
The Domain and Path properties have always been the second layer of cookie permissions.
Cookies can be passed through AJAX requests
Cookies can be propagated through AJAX requests. AJAX requests are asynchronous HTTP requests made using JS (XMLHttpRequest or Fetch) to fetch data and send it back to the backend.
Consider another example from Flask with a template that in turn loads a JS file:
from flask import Flask, make_response, render_template
app = Flask(__name__)
@app.route("/", methods=["GET"])
def index():
return render_template("index.html")
@app.route("/get-cookie/", methods=["GET"])
def get_cookie():
response = make_response("Here, take some cookie!")
response.set_cookie(key="id", value="3db4adj3d")
return response
Here is the templates/index.html
template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button>FETCH</button>
</body>
<script src="{{ url_for('static', filename='index.js') }}"></script>
</html>
Here is the content of static/index.js
:
const button = document.getElementsByTagName("button")[0];
button.addEventListener("click", function() {
getACookie();
});
function getACookie() {
fetch("/get-cookie/")
.then(response => {
// make sure to check response.ok in the real world!
return response.text();
})
.then(text => console.log(text));
}
When visiting http://127.0.0.1:5000/
we see a button. By clicking the button, we make a get request to /get-cookie/
and get the cookie. As expected, the cookie lands in the browser's cookie storage.
Make some changes to the Flask app, adding one more route:
from flask import Flask, make_response, request, render_template, jsonify
app = Flask(__name__)
@app.route("/", methods=["GET"])
def index():
return render_template("index.html")
@app.route("/get-cookie/", methods=["GET"])
def get_cookie():
response = make_response("Here, take some cookie!")
response.set_cookie(key="id", value="3db4adj3d")
return response
@app.route("/api/cities/", methods=["GET"])
def cities():
if request.cookies["id"] == "3db4adj3d":
cities = [{"name": "Rome", "id": 1}, {"name": "Siena", "id": 2}]
return jsonify(cities)
return jsonify(msg="Ops!")
In addition, adjust the JS code to request the newly added route:
const button = document.getElementsByTagName("button")[0];
button.addEventListener("click", function() {
getACookie().then(() => getData());
});
function getACookie() {
return fetch("/get-cookie/").then(response => {
// make sure to check response.ok in the real world!
return Promise.resolve("All good, fetch the data");
});
}
function getData() {
fetch("/api/cities/")
.then(response => {
// make sure to check response.ok in the real world!
return response.json();
})
.then(json => console.log(json));
When visiting http://127.0.0.1:5000/
we see a button. By clicking the button, we make a get request to /get-cookie/
to get the cookie. After the cookie appears, we will make another Fetch request to /api/cities/
.
In the browser's console, you can see the data returned by the request. In addition, in the Network
tab of the developer tools, you can see a header called Cookie, which is passed to the backend through an AJAX request.
Exchanging cookies back and forth between frontend and backend works fine as long as the frontend is in the same context as the backend: we say they come from the same origin.
This is because by default, Fetch only sends credentials when the request arrives at the origin that triggered the request, i.e. Cookie
.
Cookies cannot always be passed through AJAX requests
Consider another case, running independently on the backend, the application can be started like this:
FLASK_ENV=development FLASK_APP=flask_app.py flask run
Now, in a different folder than the Flask app, create index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button>FETCH</button>
</body>
<script src="index.js"></script>
</html>
Create a JS file named index.js
in the same folder with the following code:
button.addEventListener("click", function() {
getACookie().then(() => getData());
});
function getACookie() {
return fetch("http://localhost:5000/get-cookie/").then(response => {
// make sure to check response.ok in the real world!
return Promise.resolve("All good, fetch the data");
});
}
function getData() {
fetch("http://localhost:5000/api/cities/")
.then(response => {
// make sure to check response.ok in the real world!
return response.json();
})
.then(json => console.log(json));
}
In the same folder, from a terminal run:
npx serve
This command gives you the local 地址/端口
to connect to, for example http://localhost:42091/
. Visit the page and try to click the button with the browser console open. In the console, you can see:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/get-cookie/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
Because http://localhost:5000/
--- is different from http://localhost:42091/.
. They are different domains, so there will be a limitation of CORS
.
Everyone said that there is no project to write on the resume, so I helped you find a project, and also included a [Building Tutorial] .
Handling CORS
CORS is a W3C standard whose full name is "Cross-origin resource sharing". It allows browsers to issue XMLHttpRequest requests to cross-domain servers, thus overcoming the limitation that AJAX can only be used with the same origin.
The entire CORS communication process is completed automatically by the browser and does not require user participation. For developers, CORS communication is no different from ordinary AJAX communication, and the code is exactly the same. Once the browser finds that the AJAX request is cross-domain, it will automatically add some additional header information, and sometimes an additional request will be made, but the user will not be aware of it. Therefore, the key to implementing CORS communication is the server. Cross-domain communication is possible as long as the server implements the CORS interface.
By default, browsers will block AJAX requests to remote resources that are not of the same origin unless the server sets a specific HTTP header of Access-Control-Allow-Origin
.
To fix this first error, we need to configure CORS for Flask:
pip install flask-cors
Then apply CORS to Flask:
from flask import Flask, make_response, request, render_template, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app=app)
@app.route("/", methods=["GET"])
def index():
return render_template("index.html")
@app.route("/get-cookie/", methods=["GET"])
def get_cookie():
response = make_response("Here, take some cookie!")
response.set_cookie(key="id", value="3db4adj3d")
return response
@app.route("/api/cities/", methods=["GET"])
def cities():
if request.cookies["id"] == "3db4adj3d":
cities = [{"name": "Rome", "id": 1}, {"name": "Siena", "id": 2}]
return jsonify(cities)
return jsonify(msg="Ops!")
Now try clicking the button again with the browser console open. In the console you should see
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/api/cities/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
Although we made the same mistake, the culprit this time was the second route.
You can confirm by looking at the request in the "Network" tab that no such cookies are being sent:
In order to include cookies in Fetch requests from different origins, we have to mention the credentials
flag (by default, it is the same origin).
Without this flag, Fetch ignores cookies, which can be fixed like this:
const button = document.getElementsByTagName("button")[0];
button.addEventListener("click", function() {
getACookie().then(() => getData());
});
function getACookie() {
return fetch("http://localhost:5000/get-cookie/", {
credentials: "include"
}).then(response => {
// make sure to check response.ok in the real world!
return Promise.resolve("All good, fetch the data");
});
}
function getData() {
fetch("http://localhost:5000/api/cities/", {
credentials: "include"
})
.then(response => {
// make sure to check response.ok in the real world!
return response.json();
})
.then(json => console.log(json));
}
credentials: "include"
must be present in the first Fetch request to save the cookie in the browser's cookie storage:
fetch("http://localhost:5000/get-cookie/", {
credentials: "include"
})
It must also be present on the second request to allow the cookie to be transferred back to the backend
fetch("http://localhost:5000/api/cities/", {
credentials: "include"
})
Try again, we also need to fix another bug in the backend:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/get-cookie/. (Reason: expected ‘true’ in CORS header ‘Access-Control-Allow-Credentials’).
To allow cookies to be transmitted in CORS requests, the backend also needs to set the Access-Control-Allow-Credentials
header.
CORS(app=app, supports_credentials=True)
Important: In order for cookies to be passed through AJAX requests between different origins, this can be done:
- credentials: "include" is used in front-end fetch requests
-
Access-Control-Allow-Credentials
andAccess-Control-Allow-Origin
for the backend
Cookies can be passed through AJAX requests, but they must obey the domain rules we described earlier.
Cookie's Secure attribute
The Secure attribute means that if a cookie is set Secure=true
, then the cookie can only be sent to the server using the https protocol, but not using the http protocol. In other words, the cookie is created under the condition of https
, and its Secure=true, then you have been using https to visit other pages (such as clicking on other sub-pages after logging in), the cookie will be Sent to the server, you can jump to other pages without logging in again. But if you change the url to http protocol to access other pages, you need to log in again, because this cookie cannot be sent in http protocol.
The Secure property can be set like this
response.set_cookie(key="id", value="3db4adj3d", secure=True)
If you want to try it in a real environment, you can run the following command, and note that curl
is not passed here HTTP
save the cookie:
curl -I http://serene-bastion-01422.herokuapp.com/get-secure-cookie/ --cookie-jar -
Instead, over HTTPS, the cookie appears in cookie jar
:
curl -I https://serene-bastion-01422.herokuapp.com/get-secure-cookie/ --cookie-jar -
cookie jar file:
serene-bastion-01422.herokuapp.com FALSE / TRUE 0
Don't be fooled by Secure
: the browser accepts cookies via HTTPS
, but once the cookie enters the browser, there is no protection.
Because cookies with Secure are generally not used to transmit sensitive data.
HttpOnly attribute of cookies
If the HttpOnly attribute is set in the cookie, the cookie information cannot be read through the js script, which can effectively prevent XSS attacks and steal the cookie content, thus increasing the security of the cookie. Even so, do not put important information Store cookies.
The full name of XSS is Cross SiteScript, cross-site scripting attack, which is a common vulnerability in Web programs. XSS is a passive and client-side attack method, so its harmfulness is easily ignored. The principle is that an attacker enters (passes in) malicious HTML code into a website with XSS vulnerabilities. When other users browse the website, this HTML code will be automatically executed, thereby achieving the purpose of the attack. For example, stealing user cookies, destroying page structure, redirecting to other websites, etc.
If you have set HttpOnly it looks like this:
Set-Cookie: "id=3db4adj3d; HttpOnly"
in Flask
response.set_cookie(key="id", value="3db4adj3d", httponly=True)
In this way, the cookie is set with the HttpOnly
attribute, then the cookie information cannot be read through the js script. If checked in the console, document.cookie
will return an empty string.
When to use HttpOnly
? Cookies should always be HttpOnly
unless there is a specific requirement to expose them to runtime JS.
Terrible SameSite Properties
first-party cookies and third-party cookies
View the cookies carried in https://serene-bastion-01422.herokuapp.com/get-cookie/
Set-Cookie: simplecookiename=c00l-c00k13; Path=/
first-party
refers to the cookie issued by the website you log in or use, while third-party
cookie is often some advertising websites, which may violate privacy and security risks.
We call this type of cookie first-party
. That is, I visit the URL in the browser, and if I visit the same URL or another path to the site (let's say the Path is /
), the browser sends the cookie back to the site .
Now consider another web page at https://serene-bastion-01422.herokuapp.com/get-frog/
. The page sets a cookie, and in addition, it loads images from a remote resource hosted by 从https://www.valentinog.com/cookie-frog.jpg
.
The remote resource will in turn set a cookie by itself:
We refer to such cookies as third-party
(third party) cookies.
In addition to being used for CSRF attacks, third-party cookies can also be used for user tracking. For example, Facebook inserts an invisible image on a third-party website.
![](facebook.com)
When the browser loads the above code, it will send a request to Facebook with a cookie, so that Facebook will know who you are and what website you are visiting.
Using the SameSite property
The SameSite attribute of the cookie is used to restrict the third-party
cookie, thereby reducing security risks. It can set three values.
- Strict
- Lax
- None
Strict
is the most strict, completely prohibits third-party cookies, and will not send cookies under any circumstances when crossing sites. In other words, only the URL of the current web page is consistent with the request target, the cookie will be brought.
Set-Cookie: CookieName=CookieValue; SameSite=Strict;
This rule is too strict and may result in a very bad user experience. For example, if the current web page has a GitHub link, the user will not have GitHub's cookie when they click to jump, and the jump is always in the state of not logged in.
Lax
rules are slightly relaxed, and third-party cookies are not sent in most cases, except for Get requests that navigate to the destination URL.
Set-Cookie: CookieName=CookieValue; SameSite=Lax;
A GET request for navigating to a destination URL includes only three cases: a link, a preload request, and a GET form. See the table below for details.
After setting Strict
or Lax
, CSRF attack is basically eliminated. Of course, the premise is that the user's browser supports the SameSite
attribute.
Chrome plans to make Lax
the default. At this time, the website can choose to explicitly close the SameSite
attribute and set it to None. However, the premise is that the Secure
attribute must be set at the same time (Cookies can only be sent through the HTTPS protocol), otherwise it will be invalid.
The following settings are invalid.
Set-Cookie: widget_session=abc123; SameSite=None
The following settings are valid.
Set-Cookie: widget_session=abc123; SameSite=None; Secure
Cookies and Authentication
Authentication is one of the most challenging tasks in web development. There seems to be a lot of confusion on this topic, as token-based authentication in JWT
seems to be replacing "old", reliable modes like session-based authentication.
Let's see what role cookies play here.
session-based authentication
Authentication is one of the most common use cases for cookies.
When you visit a website that requests authentication, the backend will send a Set-Cookie
header to the frontend in the background via credential submission (e.g. via a form).
A session cookie of type is as follows:
Set-Cookie: sessionid=sty1z3kz11mpqxjv648mqwlx4ginpt6c; expires=Tue, 09 Jun 2020 15:46:52 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax
In this Set-Cookie
header, the server can include a file named session
, session id
or similar cookie
.
This is a unique identifier that is clearly visible to the browser. Whenever an authenticated user requests a new page from the backend, the browser sends back a session cookie
.
Session-based authentication is stateful because the backend must keep track of each user's session. The storage of these sessions may be:
- database
- A key/value store like Redis
- File system
Of the three session stores, something like Redis should take precedence over a database or filesystem.
Note that session-based authentication has nothing to do with the browser's session storage.
It is called a session- based session because the relevant data for user identification exists in the backend's session store, which is different from the browser's session store.
When to use session-based authentication
Use it whenever you can. Session-based authentication is the simplest, most secure, and direct form of website authentication. By default it is available on all popular web frameworks Django
etc.
However, its stateful nature is also its main disadvantage, especially when the website is served by a load balancer. In this case, techniques like sticking sessions, or storing sessions on a centralized Redis store can help.
Everyone said that there is no project to write on the resume, so I helped you find a project, and also included a [Building Tutorial] .
A note on JWTs
JWT , short for JSON Web Tokens
, is an authentication mechanism that has become increasingly popular in recent years.
JWT is great for single-page and mobile applications, but it introduces a new set of challenges. A typical flow for a front-end application that wants to authenticate against an API is as follows:
- Frontend sends credentials to backend
- The backend checks the credentials and sends back a token
- The frontend carries the token on every subsequent request
The main question that comes with this approach is: where do I store this token in the front end in order to keep the user logged in?
The most natural thing for front-end development is to save the token in localStorage
. This is bad for many reasons.
localStorage
is easily accessible from JS code, and it's an easy target for XSS attacks.
To get around this, most developers keep the JWT token in cookie
thinking that HttpOnly and Secure
would protect the cookie, at least from XSS attacks.
Setting SameSite
to strict
completely protects the JWT from CSRF attacks
The new SameSite
property set to SameSite = Strict
will also protect your "cooked" JWT from CSRF attacks. However, since SameSite = Strict
does not send cookies on cross-origin requests, this also completely invalidates the use case for JWT.
What about SameSite=Lax
? This mode allows cookies to be sent back using secure HTTP methods (i.e. GET, HEAD, OPTIONS and TRACE). POST requests do not transmit cookies in either way.
Actually, it is not a good idea to store the JWT
tag in cookie
or localStorage
.
If you really want to use JWT instead of sticking to session-based authentication and extending the session store, you might want to use JWT
with a refresh token to keep the user logged in.
Summarize
HTTP cookies have been around since 1994, they are everywhere.
Cookies are simple text strings, but their permissions can be controlled by Domain and Path
. Cookies with Secure can only be transmitted over HTTPS, while HttpOnly
can be used from JS is hidden.
However, for all intended uses, cookies can expose users to attacks and vulnerabilities.
Browser vendors and the Internet Engineering Task Force have worked year after year to improve cookie security, the most recent step being SameSite
.
So, what constitutes a relatively secure cookie? , the following points:
- Use HTTPS only
- With the HttpOnly attribute as much as possible
- Correct SameSite configuration
- Does not carry sensitive data
Talents' [Three Links] is the biggest motivation for Xiaozhi to keep sharing. If there are any mistakes and suggestions in this blog, you are welcome to leave a message. Finally, thank you for watching.
The bugs that may exist after the code is deployed cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, I recommend a useful bug monitoring tool , Fundebug .
Original: https://gizmodo.com/the-complete-guide-to-cookies-and-all-the-stuff-w-1794247382
comminicate
If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。