4

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 manipulate cookies
How is the session scheme implemented and what are the problems?
How is the token scheme implemented, how is it encoded and tamper-proof? What does jwt do? The realization and significance of refresh token
What are the similarities, differences and advantages and disadvantages of session and token
What is single sign-on? Implementation ideas and processing under the browser


Speaking from the state
HTTP stateless
We know that HTTP is stateless. In other words, the state cannot be maintained between the HTTP requester and the responder. It is all one-off, and it does not know what happened to the previous and subsequent requests.
But in some scenarios, we need to maintain state. Most typically, a user logs into Weibo, publishes, follows, and comments, all of which should be in the user status after logging in.
mark
What is the solution? mark.

At a school or company, starting from the day of enrollment, your identity and account information will be entered, and then a card will be issued to you. In the future, you only need to swipe this card for access control, check-in, and consumption in the park.

Front-end storage
This involves one issue, one deposit, and one area. The post is easy to handle. The login interface is directly returned to the front end, and the storage needs the front end to find a way.

The premise is that you have to carry the card with you.

There are many front-end storage methods.

  • The most beautiful thing is to hang on global variables, but this is an "experience card", and it will disappear once the page is refreshed.
  • The high-end point is stored in cookies, localStorage, etc. This is a "membership card". No matter how you refresh it, as long as the browser is not cleared or expired, it will remain in this state.

The front-end storage is not expanded here.
If you have a place to save it, you can put it in the parameter and bring it to the interface when you request it.

Cornerstone: cookie

But the front end is so troublesome. I have to save it myself and find a way to take it out. Is there anything I need to worry about?

Yes, cookies.

  • Cookie is also a kind of front-end storage, but compared to other methods such as localStorage, with the help of HTTP headers and browser capabilities, cookies can be front-end unaware.
    The general process is like this:

In the interface that provides the mark, the Set-Cookie field of the HTTP return header is directly "seed" to the browser
When the browser initiates a request, it will automatically bring the cookie to the interface through the Cookie field of the HTTP request header

configuration: Domain / Path

You can't take the Tsinghua campus card into Peking University.

The cookie is to limit the "spatial range" through the Domain/Path two levels.

The Domain attribute specifies which domain names should be attached to this cookie when the browser sends an HTTP request. If this attribute is not specified, the browser will set it as the first-level domain name of the current URL by default. For example, www.example.com will be set to example.com, and if you visit any subdomain of example.com in the future, HTTP requests will also be Bring 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 will reject the cookie.
The Path attribute specifies which path should be attached to this cookie when the browser sends an HTTP request. As long as the browser finds that the Path attribute is the beginning part of the HTTP request path, it will carry this cookie in the header. For example, if the PATH attribute is /, the request /docs path will also include the cookie. Of course, the premise is that the domain names must be consistent.
—— Cookie — JavaScript Standard Reference Course (alpha)

configuration: Expires / Max-Age

The card won’t work after you graduate.

Cookies can also limit the "time range" through one of Expires and Max-Age.

The Expires attribute specifies a specific expiration time. After the specified time, the browser no longer retains this cookie. Its value is in UTC format. If this attribute is not set or set to null, the cookie is only valid in the current session (session). Once the browser window is closed and the current session ends, the cookie will be deleted. In addition, the browser determines whether the cookie expires according to the local time. Because the local time is inaccurate, there is no way to guarantee that the cookie will expire at the time specified by the server.
The Max-Age attribute specifies the number of seconds that the cookie exists from now on, such as 60 60 24 * 365 (that is, one year). After this time, the browser no longer retains this cookie.
If Expires and Max-Age are specified at the same time, the value of Max-Age will take precedence.
If the Set-Cookie field does not specify Expires or Max-Age attributes, then this cookie is a Session Cookie, that is, it only exists in this conversation. Once the user closes the browser, the browser will not retain this cookie.
—— Cookie — JavaScript standard reference tutorial (alpha)

Configuration: Secure / HttpOnly

Some schools stipulate that they are not allowed to swipe without the card holder (what a strange school, suppose); some schools do not allow themselves to put stickers on the cards.

Cookie can limit "how to use".

The Secure attribute specifies that the browser can only send this cookie to the server under the encryption protocol HTTPS. On the other hand, if the current protocol is HTTP, the browser will automatically ignore the Secure attribute sent by the server. This attribute is just a switch and does not need to specify a value. If the communication is HTTPS protocol, the switch is automatically turned on.
The HttpOnly attribute specifies that the Cookie cannot be obtained through JavaScript scripts, mainly because the Document.cookie attribute, XMLHttpRequest object and Request API cannot get this attribute. This prevents the cookie from being read by the script, and the cookie will only be carried when the browser sends an HTTP request.
—— Cookie — JavaScript Standard Reference Course (alpha)

HTTP header to 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 "one (and only one)" cookie to the browser. The format is cookie key value + configuration key value. E.g:

Set-Cookie: username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

What if I want to set more cookies at once? Give more Set-Cookie headers (repetitions are allowed 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

The Cookie header of the HTTP request is used by the browser to send all cookies that conform to the current "space, time, and usage" configuration to the server. Because the browser makes the screening judgment, there is no need to return the configuration content, just send the key value.
Cookie: username=jimu; height=180; weight=80
Front-end reading and writing of cookies
The front end can create cookie . If the cookie created by the server does not add HttpOnly , then congratulations, you can also modify the cookie he gave.
Call document.cookie to create and modify cookie . Like HTTP , document.cookie can and only operate one cookie a time.

document.cookie = 'username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly';

Calling document.cookie can also read cookie , which is the HTTP , which can read all non- HttpOnly cookie .

console.log(document.cookie);
// username=jimu; height=180; weight=80

After understanding cookie , we know that cookie is the most convenient way to maintain the HTTP request status. Most front-end authentication problems are solved cookie Of course, other storage methods can also be selected (more or less mentioned later).

With the storage tool, what should we do next?


Application scheme: server-side session

Thinking back now, what happened when you swiped your card?

In fact, there is only one id (maybe your student number) saved on your card. When you swipe it, the property system will check your information and account, and then decide "can you enter this door", "which account to deduct money from this chicken leg" ".

This kind of operation is called session in the front-end and back-end authentication system.
Typical session login/verification process:

  • Browser login to send account password, server check user database, verify 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
  • After that, the browser requests the service interface again, and the sessionId is brought with the cookie
  • The server checks the sessionId to verify the session
  • After success, do business processing normally and return the result

Session storage method
Obviously, the server just gives the cookie a sessionId, and the specific content of the session (may include user information, session status, etc.), you have to save it yourself. There are several ways of storage:

  • Redis (recommended): In-memory database, redis Chinese official website. It is stored in the form of key-value, which fits the scenario of sessionId-sessionData; and the access is fast.
  • Memory: Put it directly into the variable. Once the service is restarted, it is gone
  • Database: ordinary database. The performance is not high.

Session expiration and destruction

It's very simple, just destroy the stored session data.

Session's distributed problem

Usually the server is a cluster, and when a user requests it, it will go through load balancing once, not necessarily on which machine. Then once the user's subsequent interface request machine is inconsistent with the machine he logged in to, or the machine requested to log in is down, won't the session become invalid?

There are several solutions to this problem.

  • One is to centrally store sessions from the perspective of "storage". If we use a standalone Redis or ordinary database, we can store all sessions in a library.
  • The second is from the perspective of "distribution", so that requests of the same IP are hit on the same machine during load balancing. Take nginx as an example, you can configure ip_hash to achieve this.

However, the first method is usually used, because the second method is equivalent to castration of load balancing, and it still does not solve the problem of "machine downtime requested by the user".

Session processing under node.js
The previous figure is very clear, the server has to implement access to cookies and sessions, and there are still many things to do. In npm , there are already packaged middleware, such as express-session - npm , the usage is not posted.
This is its kind of cookie:

express-session-npm mainly implements:

  • Encapsulates the read and write operations on the cookie, and provides configuration item configuration fields, encryption methods, expiration time, etc.
  • Encapsulates the access operations to the session, and provides configuration items to configure the session storage mode (memory/redis), storage rules, etc.
  • Provides session attributes to req, controls the set/get of attributes and responds to cookie and session access, and provides some methods to req.session.

Application scheme: token

The maintenance of the session has caused a lot of trouble on the server. We must find a place to store it, and we must also consider the issue of distribution, and even enable a set of Redis clusters for it alone. Is there a better way?

I also thought of schools. Before campus card technology, we all relied on "student IDs."
The doorman directly compares the faces on my student ID card and confirms the validity period, grade and other information of the student ID card, and then it can be released.

Thinking back to it, a login scenario does not need to store too much in the session, so why not just pack it into a cookie? In this way, the server doesn't need to save it. It only needs to verify the validity of the "certificate" carried by the cookie each time, and it can also carry some lightweight information.
This method is usually called a token.

token is like this:

  • The user logs in, the server verifies the account password, and obtains user information
  • Encode user information and token configuration into token, and send it to the browser through cookie set
  • After that, the user requests the business interface and carries the token through the cookie
  • The interface verifies the validity of the token and performs normal business interface processing

Storage method of client token
As mentioned in the cookie earlier, cookies are not the only way for the client to store credentials. Token because of its "statelessness", the validity period and usage restrictions are included in the content of the token, and the ability to manage cookies is less dependent, and the client is more free to store. But the mainstream way of web applications is still in cookies, after all, less worry.

expiration

So how do we control the validity period of the token? It's very simple, just stuff the "expiration time" with the data, and just judge it when verifying.

Encoding of token


The way of coding is rich and frugal.
base64
For example, cookie-session on node-npm library

Don't worry about the name, it's actually a token library, but it maintains a highly consistent usage with express-session-npm, and hangs the data to be stored on the session

In the default configuration, when I give him a userid, he will save it like this:

The eyJ1c2VyaWQiOiJhIn0= here is {"userid":"abb”} the base64 of 0611b0318938b5

Tamper

The question is, if the user cdd {"userid":"abb”} to base64, and then manually changes his token to eyJ1c2VyaWQiOiJhIn0= , will he be able to directly access the abb data?

Yes. So depending on the situation, if the token involves sensitive permissions, we must find a way to prevent the token from being tampered with.

The solution is to add a signature to the token to identify whether the token has been tampered with. For example, in the cookie-session-npm library, add two configurations:

secret: 'iAmSecret',
signed: true,

There will be a variety of .sig cookie , the value inside is {"userid":"abb”} and iAmSecret calculated by the encryption algorithm, common such as HMACSHA256 class (System.Security.Cryptography) | Microsoft Docs。

Okay, now although eyJ1c2VyaWQiOiJhIn0= can forge 0611b031893966, it can't forge the content of sig because he doesn't know the secret.

JWT

However, the above approach added an additional number of cookie , and the data itself did not have a standardized format, so JSON Web Token Introduction - jwt.io turned out.

JSON Web Token (JWT) is an open standard that defines a way to transmit JSON information. This information is trusted by digital signatures.

It is a mature token string generation scheme, including the data and signatures we mentioned earlier. It's better to look directly at what a JWT token looks like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhIiwiaWF0IjoxNTUxOTUxOTk4fQ.2jf3kl_uKWRkwjOP6uQRJFqMlwSABcgqqcJofFH5XCo 

How is this bunch of things generated? Look at the picture:

Type, encryption algorithm options, and JWT standard data fields, please refer to RFC 7519-JSON Web Token (JWT)

There are also related library implementations on node: express-jwt-npm koa-jwt-npm

refresh token


Token, as the authority guardian, the most important thing is "security".

The token used by the business interface for authentication is called an access token. The more privilege-sensitive business, the more we hope that the access token's validity period is short enough to avoid theft. However, a too short validity period will cause the access token to expire frequently. What should I do after it expires?

One way is to ask the user to log in again to get a new token, which is obviously not friendly enough. It is important to know that some access tokens may only expire in a few minutes.

Another way is to come with another token, a token that specifically generates an access token, we call it a refresh token.

  • Access token is used to access the business interface, because the validity period is short enough, the risk of embezzlement is small, and the request method can be more relaxed and flexible
  • The refresh token is used to obtain the access token. The validity period can be longer, and security can be increased through independent services and strict request methods; since it is not often verified, it can also be processed like the previous session.

With the refresh token, the request process for several situations becomes like this:

If the refresh token has expired, you can only log in again.

session and token


Both session and token are concepts with very fuzzy boundaries. As mentioned earlier, refresh tokens may also be organized and maintained in the form of sessions.

In a narrow sense, we usually think that session is an authentication scheme that is "planted on the cookie and the data is stored on the server", and the token is an authentication scheme that "the client is stored anywhere, and the data is stored in the token". The comparison of session and token is essentially a comparison of "client saves cookies / saves other places" and "server saves data / does not save data".

Client save cookie / save another place
Although saving cookies is convenient and not to worry about, the problem is also obvious:

On the browser side, cookies can be used (in fact, tokens are commonly used cookies), but out of the browser side, what if there is no cookie?
Cookies are automatically carried by the browser under the domain, which is easy to cause CSRF attacks (Front-end security series (2): How to prevent CSRF attacks?

Save it elsewhere, you can solve the scenario without cookies; Manually through parameters and other methods, you can avoid CSRF attacks.

server stores data / does not store data

  • Data storage: The request only needs to carry the id, which can greatly shorten the length of the authentication string and reduce the size of the request
  • No data storage: No need for a complete set of solutions and distributed processing on the server side, reducing hardware costs; avoiding verification delays caused by database checking

sign in

As we have already known before, in the client/server authentication system under the same domain, the client carries the credential to maintain the login status for a period of time.

But as we have more and more business lines, there will be more business systems scattered under different domain names, and the ability of "one login, universal across the board" is required, called "single sign-on".

"False" single sign-on (same primary domain name)

Simply, if the business systems are all under the same primary domain name, such as wenku.baidu.com tieba.baidu.com , it will be easy. You can directly set cookie domain as the main domain name baidu.com , which is what Baidu does.

"Real" single sign-on (different main domain name)

For example, Didi, which also owns domain names didichuxing.com xiaojukeji.com didiglobal.com cookie is completely inevitable.
This is a true single sign-on if it can achieve "one time login, universal across the board".
In this scenario, we need an independent authentication service, usually called SSO.

A complete process of "logging in from system A to system B without logging in"

  • User enters system A without login credentials (ticket), system A jumps to SSO for him
  • SSO has never logged in, and there is no sso system. There is no credential (note that this is different from the previous A ticket). Enter the account and password to log in
  • The SSO account password is successfully verified, and two things are returned through the interface: one is to download the credentials under the sso system (record the user's SSO login status); the other is to issue a ticket
  • The client gets the ticket and saves it, with the request system A interface
  • System A verifies the ticket and processes the business request normally after success
  • At this time, the user enters system B for the first time, without login credentials (ticket), system B jumps to SSO for him
  • SSO logged in, there are credentials under the system, no need to log in again, just issue a ticket
  • The client gets the ticket and saves it, with the request system B interface

full version: consider the browser scenario

The above process seems to be no problem. In fact, it is enough for many APPs to wait for the end. But it may not be easy to use under the browser.

For the browser, how should the data returned under the SSO domain be stored so that it can be brought along when accessing A? Browsers have strict restrictions on cross-domain, cookie, localStorage and other methods are domain restrictions.

This requires and only A can provide the ability to store credentials under the A domain. Generally we do this:

In the figure, we use color to mark the domain name where the browser is currently located. Note the change in the description of the gray-bottomed text in the figure.

  • In the SSO domain, SSO does not return the ticket directly through an interface, but redirects it 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 the A domain and accesses the callback interface of A with the code. The callback interface exchanges the code for the ticket
  • This code is different from the ticket, the code is a one-time, exposed in the URL, just to pass it to change the ticket, it will be invalid after the change
  • After the callback interface gets the ticket, the cookie is successfully set in its own domain
  • In subsequent requests, you only need to parse the ticket in the cookie and go to SSO for verification.
    The same is true for accessing system B

Summarize

  • HTTP is stateless, in order to maintain the front and back requests, the front-end storage mark is required
  • Cookie is a perfect marking method. It is operated by HTTP header or js, and has corresponding security policies. It is the cornerstone of most state management solutions.
  • Session is a state management solution. The front-end stores id through cookies and the back-end stores data, but the back-end has to deal with distributed issues.
  • Token is another state management solution. Compared with session, no back-end storage is required. All data is stored in the front-end, which liberates the back-end and releases flexibility.
  • The token encoding technology is usually based on base64, or the encryption algorithm is added to prevent tampering, jwt is a mature encoding scheme
  • In a complex system, token can be decentralized through service token and refresh token, while satisfying security and user experience
  • The comparison between session and token is the comparison between ``use cookies or not'' and ``backend storage or not''
  • Single sign-on requires systems under different domains to "log in once, all lines are universal". Usually, an independent SSO system records the login status and issues a ticket, and each business system cooperates with storage and authentication of the ticket.

Bill
163 声望11 粉丝

职业:网管