** I am a kite, the public number “ancient kite”, a both depth and breadth of programmers to encourage teachers, a plan to write poetry but write up the code of rural code farmers!

Articles will be included in JavaNewBee, and there will be a Java back-end knowledge map, which will cover the path from small white to big cow. 支那

JWT, which stands for JSON Web Token, is a very popular cross-domain authentication solution and is often used in single sign-on (SSO) scenarios.

Some people think it works so well that they don’t need redis on the server to implement the authentication process, while others think it is inherently flawed and doesn’t work at all.

Why is that?

Traditional authentication

Start with a login scenario

You usually use so many websites and apps, many of which need to log in, let’s choose a scene to talk about.

Taking an e-commerce system as an example, if you want to place an order, you need to register an account first. After you have the account, you need to enter the user name (such as mobile phone number or email) and password to complete the login process. You do not need to enter the user name and password when you log in to the system again after a period of time. You need to enter the user name and password again only when you do not log in to the system for a long time (for example, one month).

For those frequently used websites or apps, it is often so long that you do not need to enter passwords, that you can not remember the passwords of some frequently used websites or apps after changing to a new computer or mobile phone.

The early cookie-session authentication mode

In the early days of the Internet, the web dominated and the client was the browser, so cookie-session was the most commonly used authentication method in the early days. Up to now, some Web sites still use this method for authentication.

The certification process is as follows:

  1. A user logs in to the system by entering a user name or password or using the SMS verification code.
  2. After authentication, the server creates a Session information, saves the SessionID in the cookie, and sends it back to the browser.
  3. The next time the client initiates a request, the server automatically carries the cookie information and obtains the Session information through the cookie for verification.

But why it is a traditional way of authentication, because now everyone has a smart phone, many people do not use computers, usually use a variety of apps on the phone, such as Taobao, Pinduoduo, etc.. Under this trend, the traditional cookie-session encounters some problems: 1. Firstly, cookie-session can only be used in Web scenarios. If it is APP, there is no place to store cookies in APP. Currently, most products provide both Web and APP, and some products even only have APP.

2. At the very least, your product only supports web, and cross-domain issues should also be considered, but cookies are not cross-domain. Take Tmall mall for example. When you enter Tmall Mall, you will see the menus of Tmall Supermarket, Tmall International and Tmall Membership at the top. Click these menus will enter A different domain name, different domain name under the cookie is not the same, you can not get the cookie under the domain name OF B, even if it is A subdomain.

3. If it is a distributed service, Session synchronization needs to be considered. Nowadays, Internet websites and apps are basically distributed deployment, that is, there is more than one server. When a user logs in to a web page, the login action must be directed to a server. Your identity needs to be saved. The traditional way is to save sessions.

Now, here’s the problem. You visit several pages, and a request is load-balanced and routed to a different server (not the one you’re logged in to). When a request is received, the background checks the user’s identity information and permissions, so the interface starts to fetch the user information from the Session. However, this server is not the same one that logged in at that time, and does not store your Session, so the background server will assume that you are a non-logged user and cannot return data to you.

So, to avoid this, do Session synchronization. Once a server receives a login request, after the current server saves the Session, it also synchronizes with several other servers.

4. Cookie has the risk of CSRF (cross-site request forgery). Cross-site request forgery is an attack method that tricks users into performing unintended actions on currently logged Web applications. CSRF takes advantage of a site’s trust in a user’s Web browser. To put it simply, an attacker uses some technical means to trick a user’s browser into visiting a previously authenticated website and performing some operations (such as buying goods). Because the browser has been authenticated, the site being visited will assume that the action was initiated by a genuine user. Let’s say I’m a hacker and I find a CSRF vulnerability in a tech site you visit regularly. Publishing articles supported HTML, so I added some dangerous content to THE HTML, such as

 <img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">
Copy the code

Assuming that SRC points to a payment address from a shopping site you normally use (for example, the real attack isn’t that simple), if you’ve logged in before and the cookie that identifies you has been saved. As soon as the IMG tag loads, this CSRF attack will kick in and pay the site without you knowing it.

Cookie – Session modified version

Since there are many problems with the traditional cookie-session authentication, the above scheme can be modified. Since cookies can not be used in APP and other non-browser, it is not necessary to use cookies as client storage, switch to other ways. What should I change it to? Local storage can be used in the Web and the client database can be used in the APP. In this way, cross-domain can be realized and CSRF can be avoided.

2. The server also does not store sessions, and saves Session information in Redis and other in-memory databases, which not only improves the speed, but also avoids Session synchronization problems;

This has been transformed into the following certification process:

  1. A user logs in to the system by entering a user name or password or using the SMS verification code.
  2. After verification, the server stores the data structure constructed by authentication information in Redis and returns the key value to the client.
  3. The client retrieves the returned key and stores it in the local storage or local database.
  4. The next time the client makes a request, append the key value to the header or request body;
  5. The server obtains authentication information from Redis according to the obtained key.

The following two figures illustrate the process of first and non-first login respectively.

After a fierce transformation like a tiger, solved the problems existing in the traditional cookie-session mode. This transformation needs to be done by the developer on the project. It will certainly be laborious and time-consuming, and there may be loopholes.

JWT appearance

JWT is an implementation of cookie-session that saves you the time to build your own wheels. JWT also has the advantage that you don’t need to store authentication information (such as tokens) on the server, it is provided entirely by the client. The server can verify the user’s legitimacy based on the decryption algorithm provided by JWT itself, and this process is secure.

If you are new to JWT, the most questionable point may be: why can JWT completely rely on the client (such as browser) to achieve authentication function, authentication information is stored in the client, how to ensure security?

JWT data structure

The final JWT form is a string consisting of a header, payload, and signature, with “in the middle.” Space. Something like this:

The head

The header is represented in JSON format and is used to specify the token type and encryption algorithm. The form is as follows, indicating that JWT format is used, and the encryption algorithm is HS256, which is the most commonly used algorithm, and there are many others.

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

Corresponding to the red header in the figure above, Base64 encoding is required.

load

It is used to store data needed by the server, such as user information, such as name, gender, age and so on. It is important to note that important confidential information, such as passwords, should not be put here.

{
  "name": "Ancient Kites."."introduce": "Handsome and handsome"
}
Copy the code

In addition, JWT specifies seven fields for developers to choose from.

  • Iss (Issuer) : indicates the issuer
  • Exp (expiration Time) : expiration time
  • Sub (subject) : indicates the topic
  • Aud (audience) : Audience
  • NBF (Not Before) : indicates the effective time
  • Iat (Issued At) : time of issue
  • Jti (JWT ID) : indicates the ID

This information is also Base64 encoded.

The signature

There is a formula for calculating signatures.

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

Using the HMACSHA256 algorithm, this method has two parameters, the first parameter is (base64 encoded header + Base64 encoded payload) connected with dots, the last parameter is a custom string key, the key should not be exposed to the client, the server should know.

use

Now that you know the structure and algorithm of JWT, how do you use it? So let’s say I have a website here.

1. When the user logs in to the website, he/she needs to enter the user name, password or SMS authentication to log in. When the login request reaches the server, the server verifies the account and password, and then calculates the JWT string and returns it to the client.

2. The client gets the JWT string and stores it in the cookie or LocalStorage of the browser.

3, send the request again, such as when asking the user to set the page, add the JWT string to the HTTP request header, or put it directly in the request body.

4. After the server gets the JWT string, it uses the head of Base64 and the load part of Base64 to calculate the signature part through HMACSHA256 algorithm, and compares the calculation result with the transmitted signature part. If the result is consistent, it indicates that there is no problem with this request. Indicates that the request is expired or invalid.

How to ensure safety

The key to ensuring security is HMACSHA256 or its type of encryption algorithm, because the encryption process is irreversible, so the key information cannot be reversed according to the JWT transmission to the front end.

In addition, different headers and payloads are encrypted with different signatures, so if someone changes the information in the payload, the encrypted result will be different from the original one, so the final verification result will be an invalid request.

Is it safe for others to get the full JWT

Let’s say the payload stores a field related to the permission level, and the robber takes the JWT string and tries to change it to a higher level. As mentioned above, in this case, he will not succeed, because the encrypted signature will be different, and the server can easily identify it.

In order to prevent theft to a greater extent, HTTPS protocol should be used instead of HTTP protocol, which can effectively prevent some intermediate hijacking attacks.

As some of you are about to say, this is not safe at all. You can easily simulate requests with JWT strings. That’s true, but if you can get it, is there any other way to get it, besides the hijacking mentioned above?

Unless the robber took your computer directly, in which case, sorry, not only JWT is not secure, any other website, any authentication method is not secure.

Although such cases are rare, it is important to set expiration times reasonably when using JWT, not too long.

A problem

One problem with JWT that has caused many development teams to abandon it is that once a JWT token is issued, there is no way for the server to discard it unless it expires. There are many applications that by default only allow the most recently logged client to work, and do not allow multiple logins. JWT cannot do this because new tokens are issued, but the old tokens are still available until they expire. In this case, the server needs to add the corresponding logic.

Commonly used JWT libraries

The JWT website lists libraries for various languages, including Java as follows.

Take java-JWT as an example.

1. Import the Maven package.

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>
Copy the code

2. On login, the create method is called to get a token, which is returned to the front end.

public static String create(a){
  try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    String token = JWT.create()
      .withIssuer("auth0")
      .withSubject("subject")
      .withClaim("name"."Ancient Kites.")
      .withClaim("introduce"."Handsome and handsome")
      .sign(algorithm);
    System.out.println(token);
    return token;
  } catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
    throwexception; }}Copy the code

3. After successful login, add the token to the header or request body for the server to verify the token.

public static Boolean verify(String token){
  try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    JWTVerifier verifier = JWT.require(algorithm)
      .withIssuer("auth0")
      .build(); //Reusable verifier instance
    DecodedJWT jwt = verifier.verify(token);
    String payload = jwt.getPayload();
    String name = jwt.getClaim("name").asString();
    String introduce = jwt.getClaim("introduce").asString();
    System.out.println(payload);
    System.out.println(name);
    System.out.println(introduce);
    return true;
  } catch (JWTVerificationException exception){
    //Invalid signature/claims
    return false; }}Copy the code

4. Create the token using the create method and verify it using the verify method.

public static void main(String[] args){
  String token = create();
  Boolean result = verify(token);
  System.out.println(result);
}
Copy the code

We get the following result

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiaW50cm9kdWNlIjoi6Iux5L-K5r2H5rSSIiwiaXNzIjoiYXV0aDAiLCJuYW1 lIjoi5Y-k5pe255qE6aOO562dIn0.ooQ1K_XyljjHf34Nv5iJvg1MQgVe6jlphxv4eeFt8pA EyJzdWIiOiJzdWJqZWN0IiwiaW50cm9kdWNlIjoi6Iux5L K5r2H5rSSIiwiaXNzIjoiYXV0aDAiLCJuYW1lIjoi5Y - k5pe255qE6aOO562dIn0 ancient kite Be handsomeCopy the code

A JWT string created using the create method can pass validation.

If I change the payload part of the JWT string, the middle part of the two dots, and then call Verify, I will get a JWTVerificationException and fail the validation.

Don’t forget to give this handsome boy a thumbs up if you think he’s good!

Public number “ancient kite”, welcome wechat search attention, become excellent together!

Java developer, full stack engineer, bug killer, good at problem solving.

Stick to original dry goods output, you can choose to pay attention to me now, or read a historical article and then pay attention to it.