Recommendations for server-side processing of JWT tokens

(generated by this thread , since it is really a question about itself, and not specific to NodeJS, etc.)

I am implementing an authentication REST API server, and I have successfully implemented the JWT token processing so that the user can log in to the / login endpoint with username / password on which the JWT token is generated from the server’s privacy and returned to the client. Then the token is transmitted from the client to the server in each request of the authenticated API, after which the server secret is used to verify the token.

However, I am trying to understand best practices for how accurately and to what extent the token needs to be verified in order to create a truly secure system. What exactly should be connected with the "verification" of the token? Is it enough that the signature can be verified using the secrecy of the server, or should I also cross-check the payload for the token and / or token for some data stored on the server?

A token-based authentication system will only be as secure as sending a username / password in each request, provided that it is equal or harder to get a token than to get a user password. However, in the examples I saw, the only information needed to create a token is the username and secret server. Does this not mean that within a minute when a malicious user receives information about the server’s secrecy, he can now issue tokens on behalf of any user, thereby having access not only to one given user, as a fact, if there was a password but actually for all user accounts?

This leads me to questions:

1) If checking the JWT token is limited to checking the signature of the token itself, based only on the integrity of the server’s secrecy or accompanied by a separate verification mechanism?

  • In some cases, I saw the sharing of tokens and server sessions, where after a successful login to the / login endpoint, a session is established. API requests check the token, and also compare the decoded data found in the token with some data stored in the session. However, using sessions means using cookies, and in a way this defeats the goal of using a token-based approach. It can also cause problems for certain customers.

  • One can imagine that the server stores all the tokens that are currently used in memcache or similar, to ensure that even if the server’s secret is compromised, so that the attacker can create “valid” tokens, only the exact tokens that were generated by the endpoint / login. Is it reasonable or just redundant / excessive?

2) If JWT signature verification is the only token verification tool, which means that server privacy integrity is a breakpoint, how do I manage server secrets? Reading from an environment variable and creating (randomized?) Once for an expanded stack? It is periodically updated or rotated (and if so, how to handle existing valid tokens that were created before rotation, but they need to be checked after rotation, maybe this is enough if the server holds on to the current and previous secret at any time)? Something else?

Maybe I'm just too paranoid when it comes to the risk of infecting the server’s secrecy, which, of course, is a more general problem that should be solved in all cryptographic situations ...

+97
security authentication token jwt secret-key
May 29 '15 at 7:06
source share
5 answers

I also played with tokens for my application. Although I am not an expert, I can share some of my impressions and thoughts on this issue.

The JWT point is essentially integrity. It provides a mechanism for your server to ensure that the token provided to it is genuine and provided by your server. A signature created through your secret is what ensures this. So, yes, if your secret has leaked in some way, this person can generate tokens that your server will consider its own. The token-based system will still be more secure than your username / password system, simply because of the verification of the signature. And in this case, if someone has your secret, your system has other security problems than someone who makes fake tokens (and even then just changing the secrecy ensures that all tokens made with the old secret are now invalid )

As for the payload, the signature will only tell you that the token provided to you was exactly the same as when your server sent it. checking that the contents of the payload is valid or appropriate for your application is obviously up to you.

For all questions:

1.) In my limited experience, it is definitely better to check your tokens with a second system. Just checking the signature means that the token was created with your secret. Storing any created tokens in some kind of database (redis, memcache / sql / mongo or some other storage) is a fantastic way to ensure that you only accept tokens created by your server. In this case, even if your secret has leaked, it will not matter much, since any tokens created will not be valid in any case. This is the approach that I use in my system: all created tokens are stored in the database (redis) and for each request, I check that the token is in my database before I accept it. Thus, tokens can be revoked for any reason, for example, tokens that were somehow released into the wild, user logout, password changes, secret changes, etc.

2.) This is what I have little experience, and this is what I am still actively studying, as I am not a security professional. If you find any resources, feel free to post them here! Currently, I just use a private key that is loaded from disk, but obviously this is far from the best or safest solution.

+52
Jun 17 '15 at
source share

Here are a few things to keep in mind when implementing JWT in your application:

  • Keep the JWT's life time relatively short and manage its life time on the server. If you do not, and in the future you will need additional information in your JWTs, you will have to either support 2 versions or wait for the expiration of your old JWTs before you can implement your changes. You can easily manage it on the server if you only look at the iat field in jwt and ignore the exp field.

  • Consider including the request URL in your JWT. For example, if you want your JWT to be used at the endpoint /my/test/path , include in your JWT a field like 'url':'/my/test/path' to ensure that it is used only along this path. Otherwise, you may find that people are starting to use your JWT at other endpoints, even for those for which they were not created. You might also consider including md5 (url) instead, since having a large URL in the JWT will eventually make the JWT much larger and they can get quite large.

  • The expiration of the JWT must be configured in each use case if the JWT is implemented in the API. For example, if you have 10 endpoints for 10 different use cases for JWTs, make sure you can force each endpoint to accept JWTs that expire at different times. This allows you to block some endpoints more than others if, for example, the data served by one endpoint is very sensitive.

  • Instead of just expiring the JWT after a certain amount of time, consider implementing JWTs that support both:

    • N Uses - You can only use N times before the expiration date and
    • expires after a certain time (if you have a one-time token, you do not want it to live forever, if not used, right?)
  • All JWT authentication errors should generate an error response header that says why the JWT authentication failed. for example, "expired", "no more uses", "recalled", etc. This helps developers understand why their JWT crashes.

  • Try to ignore the "header" of your JWTs as they skip information and give a measure of control to hackers. This mainly concerns the alg field in the header - ignore it and just assume that the header is what you want to support, as this avoids hackers trying to use the None algorithm, which removes the signature security check.

  • The JWT should include an identifier that details which application generated the token. For example, if your JWT is created by two different clients, mychat and myclassifiedsapp, then each of them should include its own project name or something similar in the iss field in the JWT, for example, iss: mychat

  • JWT should not be logged. JWT content may be registered, but not JWT itself. This ensures that developers or others cannot extract the JWT from the log files and do something for other user accounts.
  • Make sure that your JWT implementation does not allow you to use the No algorithm so that hackers do not create tokens without signing them. This class of errors can be completely avoided by ignoring the "header" of your JWT.
  • Strongly iat use iat (issued in) instead of exp (expiry) in your JWT. What for? Since iat basically means when the JWT was created, this allows you to configure on the server when the JWT expires based on the creation date. If someone goes to exp , which is 20 years in the future, JWT basically lives forever! Please note that you automatically expire JWT if their iat is in the future, but allow a bit of space (for example, 10 seconds) if the client time is slightly out of sync with the server time.
  • Consider implementing an endpoint to create JWT from the json payload, and get all your executing clients to use this endpoint to create their JWT. This ensures that you can easily resolve any security issues related to how the JWT is created in one place. We did not do this right away in our application, and now we need to slowly issue security updates on the server side of the JWT, because our 5 different clients need time to implement. Also, force your creation endpoint to accept an array of json payloads to create the JWT, and this will reduce the number of http requests arriving at this endpoint for your clients.
  • If your JWT will be used at endpoints that also support session use, make sure that you have not added anything to your JWT that would satisfy the request. You can easily do this if you make sure that your endpoint works with the session when the JWT is not provided.
  • Thus, the JWT, generally speaking, ultimately contains some kind of userId or groupId and allows access to parts of your system based on this information. Make sure that you do not allow users in one area of ​​your application to impersonate other users, especially if this provides access to sensitive data. What for? Well, even if your JWT generation process is accessible only to "internal" services, developers or other internal teams can generate JWTs to access data for any user, for example, the CEO of some random client company. For example, if your application provides access to financial records for clients, then by creating JWT, the developer can get financial reports of any company! And if a hacker infiltrates your internal network anyway, they can do the same.
  • If you intend to allow caching of any URL containing a JWT, make sure that the URL includes permissions for different users, not JWT. What for? Because users can end up with data that they should not. For example, let's say the superuser logs into your application and requests the following URL: /mysite/userInfo?jwt=XXX , and this URL is cached. They log out and after a couple of minutes a regular user logs into your application. They will get cached content - with superuser information! Typically, this happens less on the client and more on the server, especially when you use a CDN such as Akamai and allow some files to last longer. This can be fixed by including the appropriate user information in the URL and checking it on the server, even for cached requests, for example /mysite/userInfo?id=52&jwt=XXX
  • If your JWT is intended to be used as a session cookie, and should only work on the same JWT machine was created, you should consider adding JTI fields to your JWT. In essence, this is a CSRF token that ensures that your JWT cannot be transferred from one user browser to another.
+35
May 29 '17 at 17:23
source share

I don't think I'm an expert, but I would like to share some posts on Jwt.

  • 1: As Akshay said, it is better to have a second system to check your token.

    a: The way I handle this: I store a hash generated in the session store with expiration time. To verify the token, it must be issued by the server.

    b .: There is at least one thing that needs to be verified by the signature method used. eg:

     header : { "alg": "none", "typ": "JWT" } 

Some libraries that test JWT accept this code without hash checking. This means that, knowing that your salt is used to sign the token, the hacker can grant himself some rights. Always make sure that this cannot be. https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/

c .: Using a cookie with a session id would not be useful to validate your token. If someone wants to capture a lambda user session, they just need to use a sniffer (for example: wirehark). This hacker will have information at the same time.

  • 2: The same for every secret. There is always a way to find out.

The way I process it is related to point 1.a .: I have a secret mixed with a random variable. The secret is unique to each token.

However, I am trying to understand the best practices for and to what extent the token needs to be verified in order for a truly secure system.

If you need the best security, you should not blindly follow best practices. The best way is to understand what you are doing (I think this is normal when I see your question), and then evaluate the security you need. And if Mossad wants to access your sensitive data, they will always find a way. (I like this blog post: https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html )

+9
Oct 02 '15 at 9:58
source share

There are a lot of good answers here. I will integrate some of the answers that I think are most relevant, and add a few more suggestions.

1) Should the JWT token be limited to verifying the signature of the token itself, relying only on the integrity of the server’s secrecy or accompanied by a separate verification mechanism?

No, due to reasons not related to the compromise of the private key. Each time a user logs in using a username and password, the authorization server must store either the generated token or metadata about the generated token. Think of this metadata as an authorization entry. This pair of users and applications should have only one valid token or authorization at any given time. Useful metadata is the user identifier associated with the access token, application identifier and the time the access token was issued (which allows you to cancel existing access tokens and issue a new access token). In each API request, verify that the token contains the correct metadata. You need to save information about when each access token was released, so that the user can cancel existing access tokens if their credentials were compromised, and log back in and start using the new access token. This will update the database from the moment the access token is issued (authorization creation time). In each API request, verify that the access token issuance time is after the authorization time has been created.

Other security measures included non-JWT logging and the requirement for a secure signature algorithm such as SHA256.

2) If JWT signature verification is the only token verification tool, which means that server privacy integrity is a breakpoint, how do I manage server secrets?

A compromise of server secrets will allow an attacker to issue access tokens for any user, and storing access token data in step 1 will not necessarily prevent the server from accepting these access tokens. For example, let's say that the user was granted an access token, and then later the attacker generates an access token for this user. The access token authorization time will be valid.

As Akshay Dhalvala says, if your secret on the server side is compromised, then you have more problems, because this means that the attacker has broken your internal network, source code repository, or both.

However, a system to mitigate the damage of a compromised secret server and avoid keeping secrets in the source code involves secretly rotating the token using a coordination service, such as https://zookeeper.apache.org . Use the cron job to generate app secrets every few hours or so (no matter how long access tokens are available) and click on the updated secret on Zookeeper. On each application server that needs to know the secret of the token, configure the ZK client, which is updated whenever the ZK node value changes. Keep the primary and secondary secret, and each time the token secret changes, set the new token secret in the primary and old secret token to the second. Thus, existing valid tokens will be valid because they will be checked for secondary secret. By the time the secondary secret is replaced with the old primary secret, all access tokens issued with the secondary secret will have expired.

+3
Jul 15 '17 at 7:29
source share

The IETF conducts the RFC in the oAuth working group, see: https://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-05.html.

0
May 23 '19 at 15:11
source share



All Articles