JSON Web Token (ABBREVIATED JWT) is currently the most popular cross-domain authentication solution. This paper will learn about JWT and integrate it into the Spring Boot project through practice to complete the design of API interface security service.

Know the JWT

Cross-domain authentication issues

Internet services are inseparable from user authentication, and talking about user authentication cannot avoid talking about session-based authentication.

The problem with this model is that it doesn’t scale well. If it is a server cluster or a cross-domain service-oriented architecture, session data is required to be shared and each server can read sessions.

Problems with Session-based authentication:

  • Session: After each user is authenticated by our application, our application makes a record on the server to facilitate the identification of the user’s next request. Generally speaking, sessions are stored in memory. However, as the number of authenticated users increases, the overhead on the server will increase significantly.
  • Scalability: After the user is authenticated, the server makes authentication records. If the authentication records are stored in memory, it means that the user’s next request must be made on this server to obtain authorized resources, which limits the capacity of the load balancer in distributed applications. This also means limiting the application’s ability to scale.
  • CSRF: Because user identification is based on cookies, if cookies are intercepted, users are vulnerable to cross-site request forgery (CSRF) attacks.

🎯 Single sign-on (SSO) problems:

For example, website A and website B are affiliated services of the same company. Now the requirement, as long as the user login in one of the websites, then visit another website will automatically login, how to achieve?

One solution is to persist session data, writing to a database or other persistence layer (for example using Redis clusters). Upon receiving the request, the various services request data from the persistence layer. The advantage of this scheme is the clear structure, but the disadvantage is the large amount of engineering. In addition, if the persistence layer fails, it will fail in a single point.

Another option is that the server does not store session data at all; all data is stored on the client side and every request is sent back to the server. JWT is an example of such a scheme.

Why do WE need JWT

To understand why, you need to understand the application scenario of JWT — authentication in the Web-based development world.

HTTP is a stateless protocol

We know that HTTP is a stateless protocol, so if we want the server to know who we are and to simplify my operation based on my previous information, then we need the server and the client to cooperate to achieve “stateful”.

If you don’t understand, let’s do an analogy.

We go to a restaurant and even if we go there every day, the waiter there can’t remember what we ate yesterday. If you say to him, “Waiter bring me the same food as yesterday and put it on my TAB,” he can’t do that. He will not remember what you have eaten, nor will he know what your bill is, nor will he ask you for it.

This scenario uses our Web development field is HTTP protocol, it is only responsible for transmission, there is no history (what you ate yesterday) and no account password (your bill), as long as you access it according to your URL processing, processing results returned. You visit again, he returns again. This is stateless.

Session-based authentication

We need to do something extra if we want to make it smarter.

Since HTTP cannot record any of our state, the server must.

Again, if the waiter’s memory is poor, we will establish a membership mechanism in the restaurant. The restaurant will give us a membership number to distinguish different members, and the restaurant will record the consumption and bill of each membership card according to this number. Every time we only need to give the waiter the membership number, he can get our consumption information.

In Web development, the relationship between cookies and sessions, when I first visit the site, our server sends a Cookie to the browser, and the browser records a Cookie that stores our Session ID, The sessionID can be used to find a Session on the server, which can record various custom information.

As shown in the figure, cookies are stored in the browser and divided according to the domain name of the site. Cookies of different domain names will not be mixed with each other in general (please search for the detailed mechanism of cookies).

In this traditional Session mode, users keep their membership numbers and the restaurant records their personal information.

The process in question is the authentication of the classic Session mechanism.

Jwt-based authentication

Understanding the Session mechanism above makes understanding JWT much easier.

We need to store sessions generated for logged-in users on the server. These sessions may be stored in memory, disk, or database. We also need to periodically clean up expired sessions on the server.

There are many users. If the server records each user, the pressure on the server will be greater.

The JWT mechanism is designed to fill this gap.

Again, take the restaurant membership as an example, this time the restaurant did not give us the membership number, but directly gave us a membership card — the card can record some information of the user, when we take the card to the restaurant, the waiter can swipe the card to get our information.

Back to the field of Web development, is the change of content recorded in cookies, cookies directly record our specific consumption information, the server to get cookies can directly obtain our corresponding information, no longer need to record, no need to query, only need to “decode” and “verification”.

Here is a comparison of the cookies stored in Session versus JWT:

  1. The first record isSessionMechanism:The Cookie records only the SESSION IDAfter obtaining the cookie, the server needs to obtain the corresponding session according to the cookie, and then obtain the user information in the session.
  2. The second record isJWTMechanism:Store more information in cookies that directly record our specific messages(The structure of JWT is explained in detail below), the server only needs to decode the Cookie to get the information.You don’t have to query the database.

Back to the JWT mechanism, the server generates this object with a Signature to prevent users from tampering with the data. The server does not store any Session data. This simplifies server-side architecture design:

  1. The server becomes stateless, making it easier to scale.
  2. The storage cost of the original server is transferred to the client storage, which relieves the pressure of data storage and management.

On the whole, the introduction of JWT mechanism is actually a concrete realization of decentralization, which transfers the storage cost of the original server to the client storage, thus introducing the design of Session management of the server and making the processing efficiency more efficient.

The principle of JWT

JWT works like this: After the server authenticates, it generates a JSON object and sends it back to the user, as shown below.

{
  "Name": "Zhang"."Role": "Administrator"."Due Time": "At 12:10 a.m. on January 10, 2022."
}
Copy the code

In the future, the user will send back this JSON object when communicating with the server. The server identifies the user solely on this object. To prevent users from tampering with the data, the server generates this object with a signature (more on that later).

The server does not hold any session data, that is, the server becomes stateless, making it easier to scale.

JWT data structure

The actual JWT would look something like this.

It is a long string with the dot (.) in the middle. Divided into three parts. Note that there is no line break inside JWT, but it is written here as a few lines for demonstration purposes.

The three parts of JWT are as follows.

  • Header
  • Payload
  • Signature (= Signature)

Let me write it as a line, which looks like this.

Header.Payload.Signature
Copy the code

If it’s a little confusing, consider driving a truck in everyday life:

  • HeaderThe equivalent of your vanThe license plate
  • PayloadAs much as your truck pullsThe goods
  • SignatureJust your pilot’sDriving license/license

Isn’t the analogy much clearer? These three sections are described in detail below.

Header

Header is a JSON object that describes the metadata of the JWT, usually as follows:

{
  "alg": "HS256"."typ": "JWT"
}
Copy the code

Among them:

  • typ: indicates the token (token) type (typeIn the JWT protocol, there is no choice but toJWT.
  • alg: Means you are behind youSignaturePart of the encryption algorithm used.

Commonly used algorithms are HMAC SHA256 or RSA. The complete algorithm types are as follows:

Finally, convert the above JSON object into a string using the Base64URL algorithm (see below).

Payload

The Payload part is also a JSON object that stores the data that needs to be transmitted.

JWT provides seven official fields for you to choose from:

  • iss (issuer)Issued by people:
  • exp (expiration time): Expiration time
  • sub (subject)Theme:
  • aud (audience): the audience
  • nbf (Not Before): Effective time
  • iat (Issued At): Issue time
  • jti (JWT ID)Number:

In addition to official fields, you can also define Private claims in this section, as shown in the following example.

{
  "sub": "1234567890"."name": "John Doe"."admin": true
}
Copy the code

Note that by default, this section is unencrypted, unencrypted, unencrypted (repeat the important words) and anyone can read it, so don’t put your sensitive information in clear text in this section (unless you encrypted it yourself first).

The JSON object is also converted to a string using the Base64URL algorithm.

Signature

The Signature section is a Signature to the first two sections, preventing data tampering.

First, you need to specify a secret. This key is known only to the server and cannot be disclosed to users. Then, using the signature algorithm specified in the Header (HMAC SHA256 by default), generate the signature as follows.

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Copy the code

The resulting Signature is the Signature string described above.

After calculating the Signature, add the Header, Payload, and Signature parts into a string, and use dots (.) between each part. Split, and now you have a JWT – is it so simple that you choke? !

Development: Base64URL

As mentioned earlier, Header and Payload are serialized using Base64URL. This algorithm is basically similar to the Base64 algorithm, with some minor differences.

JWT as a token may be placed in a URL in some cases (such as api.example.com/?token=xxx). Base64 has three characters +, /, and =, which have special meanings in URLS and are therefore replaced: = is omitted, + is replaced with -, and/is replaced with _.

This is the Base64URL algorithm.

⭐JWT uses Base64 encoding. Note that this is not encryption, but the JWT json format is removed to a more compact form.

IO /#debugger-i… jwt. IO /#debugger-i…

Briefly explain how JWT is used

The client receives the JWT returned by the server, which can be stored in cookies or localStorage.

After that, the client takes this JWT with it every time it communicates with the server. You can put it in a Cookie and send it automatically, but that’s not cross-domain, so it’s better to put it in the HTTP request header Authorization field.

Authorization: Bearer <token>
Copy the code

⭐ Alternatively, JWT is placed in the data body of the POST request when cross-domain.

Common JWT authentication architecture

Generally, token-based authentication does not need to store user login records on the server. The architecture flow of common authentication is as follows:

As shown in the figure, there are three roles: Authentication Server (login/authorization server), User (user), and App Server (application server).

  1. Users log in through the authorization server login system, the authorization serverJWTTo the user;
  2. The user client received the messageTokenYou can store it later,Like in a Cookie or localStorage;
  3. The user accesses the application serverAPIWhen, bring JWT;
  4. The server receives the request and then validates the client with the requestTokenIf the validation succeeds, the requested data is returned to the client.

In this process, only the authentication server and the application server know what the secret key is. If the authentication server and the application server are completely separate, JWT validation of the application server can also be done by the authentication server (so JWT is also suitable for single sign-on).

As you can see, this is a stateless authentication mechanism that does not have to hold the user state in memory. User access comes with JWT, which eliminates the need to use sessions as traditional applications do, allowing for more decoupling and extension. At the same time, JWT can also save user data, reducing database access.

Strengths and weaknesses of JWT

⭐ advantage

Using JWT to secure applications provides at least the following advantages:

  1. Fewer database connections: Because of its algorithm-based authentication, fewer queries are required when using JWT (fewer data connections are not the same as no database connection), resulting in faster system response times by reducing the number of server queries to the database.
  2. Easier to build: Select if the application itself is statelessJWTCan speed up the system build process.
  3. Cross-service invocation: A authentication authority can be built to handle user authentication and signature issuance, and other application services can use their own public keys to verify user signatures in subsequent user requests without having to ask the authentication authority (in theory).
  4. Stateless: There is no need to store user state in a Session like traditional Web applications.

⭐ disadvantage

Any technology framework has its limitations and cannot be a one-size-fits-all solution, and JWT is no exception. It has the following disadvantages:

  1. Heavily dependent on secret keys:JWTBoth the generation and parsing of theSecret) and are hardcoded in the system (in external configuration files). If the secret key is accidentally leaked, the security of the system will be compromised.
  2. The biggest drawback of JWT is the inability to invalidate issued tokens: since the server does not store session state, there is no way to invalidate a token during use, or to change the token’s permissions. That is, once a JWT is issued, it remains valid until expiration, unless the server deploys additional logic.
  3. The server cannot actively push messages: The server is stateless and cannot push messages to the client in the way of Session. For example, when the expiration time is about to expire, the server cannot actively renew the user’s contract, and the client needs to initiate a renewal request to the server.
  4. Redundant data overheadA:JWTThe size of the signature is much larger than oneSessionIdMuch longer, if the payload (payload), whose length grows geometrically and requires additional network overhead at each request. If onlocalStorage.May be affected byXSSattack.

Safety risk control

Consider this question: What serious consequences would happen if the JWT token on the client side were leaked or stolen? What are the remedies?

First let’s take a look at the risks associated with using JWT:

Risks associated with using JWT

  • If JWT alone solved all the problems of user authentication, the security of the system would be fragile.
  • Due to theJWTThe token is stored in the client. Once the token stored in the client is leaked or attacked, the attacker can easily forge the user identityModify/DeleteSystem resources.
  • althoughJWTBuilt-in expiration time, but before the expiration, attackers can be unscrupulous operating system data. The validity of the user’s identity is verified by the algorithmJWTThe greatest advantage is also the greatest disadvantageToo much reliance on algorithms. In contrast to traditional user authentication measures,It usually consists of several combinations, such as mobile phone verification code, face recognition, voice recognition, fingerprint lock, etc.
  • Do user identity identification using the username and password, after the user name and password leaked, to meet a sensitive operations (such as add, modify, delete, download and upload), can use other ways to verify the legitimacy of the users (such as sending the verification code, email verification code, fingerprint information, etc.) to ensure data security.

In summary, JWT is more algorithm-based and less flexible than traditional authentication methods, and the server often performs user authentication passively, failing to isolate abnormal users in a timely manner (this is the most fundamental characteristic, and this is the focus of the examination, take notes).

In fact, whether based on Session or JWT, once the secret order is stolen, it is a tricky matter. The following steps (including but not limited to) should be taken in the event of token leakage at JWT.

Risk control measures are recommended

In order to prevent user JWT token leakage and threaten system security, system functions can be improved in the following aspects:

  • Clear the leaked tokens: The most straightforward and easy to implement. willJWTA copy of the token is also stored on the server. If an abnormal token is found, the abnormal token is removed from the server. When a user initiates a request, the user is forced to re-authenticate until the authentication succeeds. The storage of server tokens can be usedRedisSuch as the cache server for management, can also be usedEhcacheToken information is stored in memory.
  • Sensitive operation protection: In relation to sensitive operations such as add, modify, delete, upload, download, etc., regularly (30Minutes.15Minutes or less) check the user’s identity, such as mobile phone verification code, scanning qr code, and other means to confirm that the operator is the user himself. If the authentication fails, the request is terminated and the user’s identity information is reauthenticated.
  • Geography checking: Users typically access applications within a relatively fixed geographic range and can use geographic location information as an aid in screening. If you find A user by often area 1 change to 2 relatively far region, or frequent switching between multiple areas, whether is it possible for users in multiple regional activity (impossible), shall terminate the current request * *, forcing users to verify identity, issue the new JWT token, And remind (or ask) the user to reset the password **.
  • Monitor request frequencyIf:JWTSecret order theft, attackers or through some tools to forge user identity, high frequency of the system to send requests, in order to get user data. In this case, you can monitor the number of user requests per unit of time. When the number of user requests per unit of time exceeds the preset threshold, the user secret order is faulty. For example, if more than five consecutive requests are received within one second, the user is regarded as an invalid user. The server terminates the request, forcibly clears the JWT secret order of the user, and then hops back to the authentication center to authenticate the user.
  • Check: the client environment for some mobile terminal applications, can be the user information and equipment (mobile phone, tablet) binding machine code, and stored in the server, when the client initiate the request, to check whether the client machine and server match, if not match, the illegal request, subsequent requests and end users.

Best practices

Once you have a good understanding of the technical details of JWT, and the scenarios being handled, it is natural to have a set of best practices for using JWT:

  1. Be careful not to carry sensitive information when using JWT. The token is not exposed.
  2. In Web applications, don’tJWTAs aSessionUse! If you want sessions, for the most part, traditionalCookie - SessionThe mechanics work better.
  3. JWTSuitable for one-time command authentication,Issue a JWT with a very short validity period and minimal risk of exposureSince each operation generates a new JWT, there is no need to save itJWT, truly stateless.
  4. To reduce theft,JWTShould not be usedHTTPProtocol code transmission, to useHTTPSProtocol transfer.
  5. When you build a set based onJWTThe user verification, must establish a set of corresponding risk control mechanism at the same time, to ensure that the risk occurs controllable & timely stop loss.

Spring Boot integrates with JWT

Import dependence

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.0</version>
</dependency>
Copy the code

Implement the Jwt utility class

This step requires customizing JWT utility classes to generate and verify tokens.

public class JwtUtil {
    // Set the token expiration time (milliseconds) : The current value is 60 seconds
    private static final long ttl = 60 * 1000;
    / / sign Signature
    private static final String signature = "Wu-YiKun";

    public static String createToken(String username) {
        JwtBuilder jwtBuilder = Jwts.builder();

        return jwtBuilder
                .setHeaderParam("typ"."JWT")
                .setHeaderParam("alg"."HS256")
                .setId(UUID.randomUUID().toString())
                .setSubject("Access Token")
                .setExpiration(new Date(System.currentTimeMillis() + ttl))
                .setIssuer("Wu-Yikun")
                .setIssuedAt(new Date())
                .claim("userId", username)
                .claim("role"."user")
                .signWith(SignatureAlgorithm.HS256, signature)
                .compact();
    }

    public static boolean parseToken(String token) {
        if (token == null) {
            return false;
        }
        JwtParser jwtParser = Jwts.parser();
        try {
            jwtParser.setSigningKey(signature).parseClaimsJws(token);
        } catch (Exception e) {
            return false;
        }
        return true; }}Copy the code

Verify services and generate tokens

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @PostMapping("/login")
    public String loginReturnToken(@RequestBody User user) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        Map<String, String> map = new HashMap<>();
        map.put("username", user.getUsername());
        map.put("password", user.getPassword());
        queryWrapper.allEq(map);
        User selectOne = userMapper.selectOne(queryWrapper);

        if(selectOne ! =null) {
            // The login is authenticated and a valid token is generated!
            return JwtUtil.createToken(selectOne.getUsername());
        }
        return ""; }}Copy the code

The interceptor

public class AuthenticationInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");
        boolean result = JwtUtil.parseToken(token);
        return result;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}}Copy the code

Remember to configure interceptors:

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthenticationInterceptor())
            .addPathPatterns("/ * *")
            .excludePathPatterns("/user/login"); }}Copy the code

Postman request validation

Login to obtain token:

Obtain data with token:

The token request can be sent to the background to obtain data within the validity period.

Reference article:

  • What are the schemes for Session sharing in distributed architecture?
  • JSON Web Token Tutorial
  • SpringBoot integration JWT
  • JSON Web Token
  • SpringBoot integrates JWT combat

Life is dull, but when you run, it’s windy