6

Current project JWT login authentication method and problems

Current login authentication method

When the user logs in, a JWT is returned, which is stored locally by the front end. After that, every time the user makes a request to the API that requires permission, the JWT is used to verify the identity.
After the backend receives the JWT, verify that the JWT is correct and has not expired:

  1. If it is correct and not expired, the resource is returned.
  2. If it is incorrect, it will return an incorrect status code; if it has expired, it will return an expired status code, requiring you to log in again.

problem

When using JWT to implement login authentication, because JWT has a fixed expiration time, it may happen to expire during the operation of the user, and then suddenly jump to the login interface, resulting in a poor user experience.

Target

Use JWT to achieve login authentication, and only require users to log in again when they do not perform any operation on the system for a period of time, and ensure the security of JWT as much as possible.

Solution and analysis of advantages and disadvantages

Solution 1: Use only one JWT token (not recommended)

specific implementation

When the user logs in, a JWT is returned, which is stored locally by the front end. After that, every time the user makes a request to the API that requires permission, the JWT is used to verify the identity.
After the backend receives the JWT, verify that the JWT is correct:

  1. If it is not correct, the error code will be returned directly;
  2. If it is correct, verify that the JWT has expired:

    • If it is not expired, the resource will be returned directly;
    • If it expires, calculate the expiration time:

      • If the expiration time does not exceed a certain threshold, the resource and new JWT will be returned;
      • If the expiration time exceeds a certain threshold, an error code is returned. Request to log in again.
Advantages

Realize that if and only if the user does not perform any operation on the system for a period of time, the user is required to log in again.
When the JWT expires, if the user is still in the operating system, the just-expired JWT will be sent to the backend. At this time, the expiration time of the JWT does not exceed the threshold, and the resource and the new JWT are returned directly, so that the user is not aware of the latest book.
However, if the user does not have an operating system for a period of time (within the threshold) after the JWT expires, when the user operates the operating system again, the JWT with the expiration time exceeding the threshold will be sent to the backend, and the backend will return an error code to realize re-login.

Disadvantages

Security is low. If you frequently send requests, you can use a JWT to achieve permanent login. Once the JWT is stolen, the attacker can use the obtained JWT to permanently falsify the user to obtain information.

Solution 2: Use two JWT tokens (recommended)

specific implementation

When the user logs in, two JWTs (access token and refresh token) are returned, one is used to verify the identity of the requested resource, and the other is used to update the refresh token when the access token expires. Among them, the refresh token has a longer validity period (for example, 7 days), and the access token has a shorter validity period (for example, 1 hour). Stored locally by the front end. Thereafter, every time the user makes a request to an API that requires permission, he brings an access token to verify his identity.
After the backend receives the access token: verify that the access token is correct:

  1. If it is not correct, the error code will be returned directly;
  2. If it is correct, verify that the access token has expired:

    • If it has not expired, return the resource directly;
    • If it expires, it returns an expired error code. After receiving the expired error code, the front end uses the refresh token to request a new access token from the update interface, and the update interface determines whether the refresh token has expired:

      • If it has not expired, return a new access token and a new refresh token, and invalidate all previous refresh tokens generated by the same refresh token (maintain an invalid list in the update interface). The front end uses the new access token to re-issue a request to the API that needs permission to obtain resources.
      • If it expires, an error code will be returned, requiring you to log in again.
      • If a refresh token that has been invalidated is received, all current refresh tokens and access tokens that are the same user as the invalid refresh token are invalidated (specifically, the user's access is invalidated) until the user re-register.

Using this method, it can avoid the sudden jump login during the user operation (mainly solves the inconsistency between the two operations, there will be no one request but the normal access to the resources, the next time the resource is requested will suddenly jump The phenomenon of going to the login page), which can guarantee higher security.

explain
Q: Why not use a permanently valid refresh token?

A: In order to achieve higher security. Once the permanently valid refresh token is stolen, the attacker can use the token to permanently impersonate the user to obtain personal information. If you replace a refresh token with a new refresh token every time you use the refresh token, you can use the update interface to return the new refresh token while invalidating the old refresh token to prevent attackers from using the stolen refresh token to obtain a new refresh token/access. token.

Q: Why does the refresh token need to be updated at the same time when the refresh token obtains a new access token?

A: Because if the refresh token is not updated, the inconsistency between the two operations of the user cannot be avoided. It is possible that the user can still operate normally one minute before the refresh token expires. After one minute, the refresh token and access token expire at the same time, and they suddenly jump to the login page, resulting in an unfriendly user experience.

Q: Why do I invalidate the refresh token used to request the new token after obtaining the new access token and refresh token by using the refresh token?

A: In order to avoid replay attacks after the previous refresh token is stolen (use the previous refresh token to request new access token and refresh token).

Q: Why does the update interface ban all the refresh tokens obtained using the first refresh token after receiving the invalid refresh token?

A: Because I don't know which refresh token was stolen. It is possible that the attacker uses the first refresh token and uses this token to obtain a new refresh token on the update interface. At this time, the user may use the old refresh token (which has been invalidated) to request the update interface. It is also possible that after the attacker steals the first refresh token, the user first uses the token to obtain a new refresh token on the update interface. At this time, the attacker may use the old refresh token (which has been invalidated) to request the update interface. See: auth0-refresh-token-rotation

Q: When receiving an invalid refresh token, how to invalidate all refresh tokens and access tokens that are the same user as the invalid refresh token?

A:

  1. Shorten the effective time of the JWT, and then maintain a user list in the update interface to prohibit all refresh tokens for this user: but the shortest access token also has a fixed validity period (5~10min), which may provide the attacker with 5~10min to use the token time.
  2. Maintain a list of users who are forbidden to access. Each time the JWT is checked, it is judged whether it is the JWT for the user, until the user logs in again: when a refresh token is forbidden, the message is broadcast to all related servers, and all servers maintain a collection To the user list with invalid refresh token, every time an access token or refresh token is received, it is judged whether the corresponding user is on the list, and if it is, the error status code is directly returned. In this way, before the user logs in again, he cannot use an access token that has not expired to access any business interface, and he cannot use a refresh token that has not expired to obtain a new access token.
  3. see: fusionauth-revoking-jwts

JWT VS Session: How to choose login authentication

Both are to record the login status in the stateless HTTP protocol to avoid the need to verify the identity for each request.

Session implements login authentication

After the user logs in successfully, the server generates a corresponding session ID, stores it in a file or database (in memory), and returns it to the browser in a cookie. After logging in, a cookie will be sent for each request, and the session ID in the cookie is searched in the storage of the server to verify the user's identity.

Compared

  1. (Horizontal) scalability: When the number of users increases, multiple servers need to be used to handle access.

    • If you use session, you need to solve the problem of storing session ID on the server side, so you need a centralized session storage, generally a server dedicated to running redis. But this will also face the problem of traffic bottlenecks. And when there are too many people online at the same time, a large number of session IDs need to be stored, which consumes a lot of server resources.
    • If you use JWT, you don’t need to store each user’s login information on the server side (except for refresh tokens that have not expired but are disabled, but you don’t need to verify when the user requests the business interface, but only when the token is updated, which will not affect the business. Response time of the interface). Any server can directly judge whether it is a legal login user through JWT.
  2. Performance: If the JWT contains a lot of data, it will be much larger than a session ID, which will bring additional overhead to the HTTP request. But the session has to look up the database every time to verify the user's identity.
  3. Abolish all current valid authentication information of a user on the server side (for example, after the user changes the password, it is forbidden to use the original information to access the business interface):

    • If you use session: relatively simple, the only authentication information is the session ID, so you can delete the session ID directly from the database.
    • If you use JWT: more complicated. It is necessary to abolish all the access tokens and refresh tokens of a user that are still within the validity period. Once the token is issued, it can be authenticated by the server within the validity period. Therefore, it is necessary to maintain a blacklist of disabled users. Request service interface/update access token must be searched. If the corresponding user is on the blacklist, it will refuse to return business data/ New access token.
  4. How to log out:

    • If using session: delete the session ID.
    • If you use JWT: The general approach is to directly delete the JWT stored (cookie or localstorage) on the client from the client. However, after logging out, the service interface/update interface can still be accessed using the JWT that has not expired in the last login. If you want to achieve a truly complete logout on the server side, please refer to 3.

refer to


MarsTokio
43 声望1 粉丝

引用和评论

0 条评论