In this article you will see:
- HTTP – based front-end authentication background
- Why is cookie the most convenient storage solution, and what are the ways to operate cookies
- How is the session scheme implemented and what are the problems
- How is the Token scheme implemented, encoded and tamper-proof? What does JWT do? Refresh Token implementation and significance
- What are the similarities and differences, advantages and disadvantages between Session and token
- What is single sign-on? Implementation ideas and processing in the browser
Small advertising: long-term push didi: [email protected]
Let’s start with states
HTTP stateless
As we know, HTTP is stateless. That is, there is no way to maintain state between the HTTP requestor and the responder. It is all one-time, and it does not know what happened to the previous and subsequent requests.
But there are situations where we need to maintain state. Most typically, when a user logs in to weibo, he or she posts, follows and comments on it as a user after logging in.
tag
So what’s the solution? :: Marks ::.
In the school or company, your identity and account information will be recorded on the day of admission and you will be issued a card. From now on, you only need to swipe this card for access control, punching and consumption in the park.
The front store
This involves a, a deposit, the area, hair easy to do, landing interface directly back to the front end, storage needs the front end to think of a way.
That is, if you carry it with you.
The front end can be stored in many ways.
- The most lame, attached to a global variable, but it’s an “experience card” that disappears after a page refresh
- High-end point, save to cookie, localStorage, etc., which belongs to the “membership card”, no matter how to refresh, as long as the browser is not clear or expired, has been holding this state.
The front end storage is not expanded here.
There is a place to save, when the request can be spelled into the parameters brought to the interface.
Foundation: cookies
But the front end is very troublesome ah, want to own again deposit, want to think of a way to take out again, have need not worry about?
Yes, the cookie.
Cookie is also a front-end storage, but compared with localStorage and other ways, with the help of HTTP header, browser capabilities, cookie can be front-end awareness.
The general process goes like this:
- In the interface that provides the tag, the set-cookie field of the header returned via HTTP is “planted” directly to the browser
- When the browser initiates a request, it automatically brings the cookie to the interface through the cookie field in the HTTP request header
Configuration: Domain/Path
You can’t get into Peking University with tsinghua campus card.
Cookies are intended to limit :: “spatial scope” :: through the Domain/Path level.
The Domain property specifies which Domain names should accompany the Cookie when the browser makes an HTTP request. If this attribute is not specified, the browser defaults to the level 1 domain name of the current URL, such as www.example.com, as example.com, and future HTTP requests that access any subdomain of example.com will also carry this Cookie. If the domain name specified by the server in the set-cookie field does not belong to the current domain name, the browser rejects the Cookie.
The Path property specifies which paths to attach the Cookie to when the browser makes an HTTP request. Whenever the browser realizes that the Path attribute is the beginning of the HTTP request Path, it will include the Cookie in the header. For example, if the PATH attribute is /, the request /docs PATH will also contain the Cookie. Of course, the premise is that the domain name must be consistent.
Cookie — JavaScript Standard Reference Tutorial (Alpha)
Configuration: Expires/max-age
The card won’t work when you graduate.
Cookies can also limit :: “time range” :: by either Expires or Max-age.
The Expires attribute specifies a specific expiration date, after which the browser will no longer keep the Cookie. Its value is in UTC format. If this property is not set or is set to NULL, the Cookie is valid only for the current session. The Cookie is deleted once the browser window is closed and the current session ends. In addition, the browser determines whether the Cookie will expire based on the local time. Since the local time is not precise, there is no guarantee that the Cookie will expire at the time specified by the server.
The max-age property specifies the number of seconds the Cookie will exist from now on, such as 60 * 60 * 24 * 365 (a year). After this time, the browser no longer keeps the Cookie.
If both Expires and max-age are specified, the max-age value takes precedence.
If the set-cookie field does not specify an Expires or max-age attribute, the Cookie is a Session Cookie, meaning it exists only for this Session and the browser does not retain the Cookie once the user closes the browser.
Cookie — JavaScript Standard Reference Tutorial (Alpha)
Configuration: Secure/HttpOnly
Some school rules, do not bring the card cover brush (what weird school, suppose); Some schools won’t allow themselves to put stickers on the cards.
Cookies can limit :: “How to use” ::.
The Secure property specifies that the browser can send this Cookie to the server only if the encryption protocol HTTPS is used. On the other hand, if the current protocol is HTTP, the browser automatically ignores the Secure attribute sent by the server. This property is just a switch and does not need to specify a value. If the communication is HTTPS, this switch is automatically turned on.
The HttpOnly attribute specifies that the Cookie is not available through JavaScript, mainly the Document. Cookie attribute, the XMLHttpRequest object, and the Request API. This prevents the Cookie from being read by the script and is carried only when the browser makes an HTTP request.
Cookie — JavaScript Standard Reference Tutorial (Alpha)
HTTP headers read and write cookies
Looking back, how does HTTP write and pass cookies and their configuration?
A set-cookie header returned by HTTP is used to write a “one (and only one)” Cookie to the browser in the format of Cookie key + configuration key. Such as:
Set-Cookie: username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
Copy the code
What if I want to set more cookies at a time? Give more set-cookie headers (allow repetition in one HTTP request)
Set-Cookie: username=jimu; domain=jimu.com
Set-Cookie: height=180; domain=me.jimu.com
Set-Cookie: weight=80; domain=me.jimu.com
Copy the code
The Cookie header of an HTTP request is used by the browser to send all cookies that match the current configuration of space, time, and usage mode to the server. Because the browser does the filtering, there is no need to return the configuration, just send the key value.
Cookie: username=jimu; height=180; weight=80
Copy the code
The front end reads and writes cookies
The front-end can create their own cookies, if the server created cookies did not add HttpOnly, congratulations, you can also modify the cookie he gave.
Cookies can be created and modified by calling Document. cookie. Like HTTP, document.cookie can operate on only one cookie at a time.
document.cookie = 'username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly';
Copy the code
Cookies can also be read by calling document.cookie, which, like HTTP, can read all non-HttpOnly cookies.
console.log(document.cookie);
// username=jimu; height=180; weight=80
Copy the code
(With a cookie attribute, why is the read and write behavior different? Get/set
Cookies are the cornerstone of maintaining the state of HTTP requests
After understanding cookies, we know that cookies are the most convenient way to maintain the HTTP request state, and most front-end authentication problems are solved by cookies. Of course, other storage options are also available (more or less covered later).
So with the storage tool, what do we do next?
Application solution: Server session
Now, what happened when you swiped your credit card?
In fact, you only put an ID on the card (may be your student number), brush the time property system to check your information, account, and then decide “this door you can enter” “this chicken leg to which account deduction”.
This operation is called a session in the front – end authentication system.
Typical session login/authentication process:
- The browser sends the account password after login. The server checks the user database and verifies the user
- The server saves the user login status as Session and generates a sessionId
- Return through the login interface and set the sessionId to the cookie
- The browser then requests the business interface, and the sessionId comes with the cookie
- The server checks the sessionId to verify the session
- Services are processed and the result is displayed
Storage mode of the Session
Obviously, the server only gives the cookie a sessionId, and the specific content of the session (including user information, session state, etc.) needs to be saved by itself. There are several ways to store it:
- Redis (recommended) : In-memory database, Redis Chinese official website. It is stored in the form of key-value, exactly matching the sessionID-sessionData scenario. And access is fast.
- Memory: Put directly into variables. Once the service is restarted, it’s gone
- Database: common database. Poor performance.
Session expiration and destruction
It is as simple as destroying the stored session data.
Session distribution issues
Usually the server is a cluster, and the user request will go through a load balancing, not necessarily to which machine. If a user’s subsequent interface requests a different machine from the one he logged on to, or if the machine he logged on to goes down, doesn’t the session expire?
This problem can now be solved in several ways.
- First, from the perspective of “storage”, the session is stored centrally. If we use a separate Redis or regular database, we can store sessions in one repository.
- Second, from the perspective of “distribution”, the requests from the same IP address are sent to the same machine in load balancing. Using nginx as an example, you can configure ip_hash to implement this.
But the first approach is usually used because the second approach emaschews load balancing and still doesn’t solve the problem of “user-requested machine downtime.”
Session processing under Node.js
As is clear from the previous figure, there is still a lot of work to be done on the server to implement cookie and session access. In NPM, there are already packaged middleware, such as express-session-NPM, and usage is irrelevant.
Here’s the cookie it planted:
Express-session-npm implements:
- It encapsulates read and write operations on cookies and provides configuration item configuration fields, encryption modes, and expiration time.
- It encapsulates the session access operations and provides configuration items to configure the session storage mode (memory/REDis) and storage rules.
- Req provides session attributes, controls the set/ GET attributes and responds to cookies and session access, and provides methods for req.session.
Application solution: Token
The maintenance of the session caused a lot of trouble for the server side, we had to find a place to store it, we had to consider the issue of distribution, and we even had to enable a separate Redis cluster for it. Is there a better way?
Then I thought of school. Before campus card technology, we all relied on “student id cards”. The guard directly compared my face with the student ID card, confirmed the validity of the student ID, grade and other information, then I could release.
Thinking back, a login scenario doesn’t have to store much in the session, so why not just package it in cookies? In this way, the server does not need to save, and only needs to check the validity of the “certificate” of the cookie belt every time, and also can carry some lightweight information.
This approach is often called token.
The token process goes like this:
- After a user logs in, the server verifies the account password and obtains user information
- The user information and token configuration are encoded into tokens and sent to the browser through cookies
- After that, the user requests the service interface and carries the token through the cookie
- Interface To verify the validity of the token and perform normal service interface processing
Storage mode of the client token
As Cookie mentioned earlier, cookies are not the only way clients store credentials. Token because of its “stateless”, validity period, use restrictions are wrapped in the token content, the cookie management ability is less dependent, the client storage appears more free. But the dominant approach to Web applications is still to put cookies in them.
Token expired
So how do we control the validity of tokens? It’s easy to plug in the “expiration date” with the data and determine when you validate it.
Token of coding
Coding is done in a frugal way.
base64
For example, the cookie-session-npm library on node
Regardless of the name, it is actually a token library, but it maintains a highly consistent usage with express-session-nPM, holding the data to be stored in the session
By default, when I give him a userID, he saves it like this:
EyJ1c2VyaWQiOiJhIn0 = is just base64 of {” userID “:”abb “}.
tamper-proof
{” userID “:”abb “} switch to base64, and then manually change your token to eyJ1c2VyaWQiOiJhIn0=, will you be able to access abb data directly?
Yes. So it depends, if the token involves sensitive permissions, you need to find a way to avoid the token being tampered with.
The solution is to sign the token to identify if it has been tampered with. For example, in the cookie-session-nPM library, add two configurations:
secret: 'iAmSecret',
signed: true,
Copy the code
Sig cookie. The values in the cookie are {” userID “:”abb “} and iAmSecret calculated by the encryption algorithm. Common such as HMACSHA256 type (System. Security. Cryptography) | Microsoft Docs.
Ok, now CDD can forge the contents of sig, but not secret, because he doesn’t know secret.
JWT
But this added to the number of cookies, and the data itself had no formal format, so JSON Web Token Introduction-jwt. IO was born.
JSON Web Token (JWT) is an open standard that defines a way to pass JSON information. This information is digitally signed to be trusted.
It is a mature token string generation scheme that contains the data, signatures we mentioned earlier. Instead, take a look at what a JWT token looks like:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhIiwiaWF0IjoxNTUxOTUxOTk4fQ.2jf3kl_uKWRkwjOP6uQRJFqMlwSABcgqqcJofFH5 XCoCopy the code
How do you make this bunch of things? Look at the picture:
For types, encryption algorithm options, and JWT standard data fields, see RFC 7519-JSON Web Token (JWT)
Node also has a related library implementation: Express-jwt-npm KOa-jwt-npm
refresh token
Token, as the guardian of authority, the most important thing is “security”.
The tokens used by service interfaces for authentication are called Access tokens. The more permission-sensitive the business, the more we want access tokens to be valid for a short period of time to avoid theft. However, too short a validity period will cause access tokens to expire frequently. What can be done after expiration?
One option is to let users log in again to get a new token, which is obviously not friendly, given that some Access tokens can expire in minutes.
Another option is to have another token, a token that specifically generates access tokens, which we call refresh tokens.
- The Access token is used to access service interfaces. The validity period is short enough to reduce the risk of embezzlement and make the request method more flexible
- Refresh Token is used to obtain access token. The validity period can be longer and security can be enhanced through independent service and strict request. Since validation is infrequent, it can also be handled as in the previous session
With the Refresh Token, the request flow in several cases looks like this:
If the Refresh Token also expires, you can only log in again.
The session and token
Session and token are vague concepts, and as mentioned earlier, refresh tokens may also organize maintenance in the form of sessions.
In a narrow sense, we usually think of session as an authentication scheme that “stores data on cookies and servers”, while token is an authentication scheme that “stores data in tokens wherever clients can”. The comparison between session and token is essentially a comparison between “client saves cookies/other places” and “server saves data/does not save data”.
The client saves cookies/elsewhere
Although it is convenient to save cookies, the problem is also obvious:
- On the browser side, you can use cookies (in fact, cookies are often used by token), but outside the browser side, what if there is no cookie?
- Cookie is automatically carried by the browser in the domain, which is easy to cause CSRF attacks (front-end security series (2) : How to prevent CSRF attacks? – Meituan Technical Team)
Save in another place, can solve the scenario without cookies; You can avoid CSRF attacks by manually adding parameters.
Server saves data/does not save data
- Data storage: the request only needs to carry the ID, which can greatly shorten the authentication string length and reduce the request volume
- No data storage: no need for server solutions and distributed processing, reducing hardware costs; Avoid validation delays caused by library searches
Single sign-on (sso)
As we have already seen, in a client/server authentication system in the same domain, the client carries credentials to maintain login status for a period of time.
But as we have more and more lines of business, there will be more and more business systems scattered under different domain names, so we need the ability of “once login, universal”, called “single sign-on”.
“Fake” single sign-on (same main domain name)
Simple, if the business systems are under the same main domain name, such as wenku.baidu.com tieba.baidu.com, it is easy to handle. You can directly set the cookie domain to the master domain name baidu.com, which is what Baidu did.
“Real” single sign-on (different primary domain name)
For example, didi such a fashionable company, also has a domain name such as Didichuxing.com xiaojukeji.com didiglobal.com, kind of cookie is completely unavoidable.
This can achieve “one login, universal”, is the real single sign-on.
In this scenario, we need a separate authentication service, often referred to as SSO.
A complete process of “triggering login from system A to system B without login”
- When A user enters system A without A ticket, system A jumps to SSO for him
- SSO has not logged in, so there is no certificate in SSO system (note that this is not the same as A ticket). Enter your account and password to log in
- After the SSO account password is successfully authenticated, the interface returns the password to perform the following operations: 1. Second, issue a ticket
- The client takes the ticket, saves it, takes the request system A interface with it
- System A verifies ticket and processes service requests properly
- When the user enters system B for the first time and does not have a ticket, system B jumps to SSO for him
- If SSO has logged in to the system, the system has a credential. Therefore, you do not need to log in again. You only need to deliver ticket
- The client takes the ticket, saves it, and comes up with the request system B interface
Full version: Consider the browser scenario
The above process looks fine, but in fact many apps and so on will be enough. But it doesn’t always work in a browser.
Look here:
How do browsers store data returned from SSO fields so that they can take it with them when accessing A? Browsers have strict restrictions on cross-domains, such as cookies and localStorage.
This requires and only allows A to provide the ability to store credentials in domain A. Here’s how we do it:
In the picture we color the domain name that the browser is currently in. Notice the change in the text on the grey background.
- In the SSO domain, SSO does not directly return ticket through an interface. Instead, SSO redirects ticket to the interface of system A through A URL with A code. This interface is usually agreed upon when A registers with SSO
- The browser is redirected to field A and accesses A’s callback interface with code. The callback interface exchanges code for ticket
- This code is different from the ticket, because the code is a one-time thing, exposed in the URL, just to pass the ticket, and then it expires
- After the callback interface gets the ticket, the cookie is set successfully in its own domain
- In subsequent requests, only the ticket in the cookie needs to be resolved for SSO verification
- Same thing with accessing system B
conclusion
- HTTP is stateless and requires a front end to store tokens in order to sustain forward and backward requests
- Cookies are a complete way of marking through HTTP headers or JS operations, with corresponding security policies, and are the cornerstone of most state management schemes
- Session is a state management scheme in which the front end stores ids through cookies and the back end stores data, but the back end handles distributed issues
- Token is another state management solution. Compared with session, all data is stored in the front end, freeing the back end and freeing flexibility
- Token encoding technology, usually base64 based, or add encryption algorithm tamper-proof, JWT is a mature encoding scheme
- In a complex system, a token can be distributed through service token and refresh token to ensure security and user experience
- The comparison between session and token is the comparison between “whether to use cookie” and “whether to store on the backend”
- Single sign-on (SSO) requires that systems in different domains log in to each other at one time. Usually, an independent SSO system records the login status and delivers a ticket. Service systems cooperate with each other to store and authenticate tickets