1

I'm building a site with Spring, which requires authentication in order for accessing certain pages.

The site is actually composed of a client host, which render the views and handle the data binding, and a REST api host (built with Spring as well), it's responsibility is returning/manipulating data, validation/generation of user token etc..

I've decided to implement a custom authentication in the REST side, upon receiving a valid username and password, it will return:

  • JWT signed by the REST API with AES-256, the payload will contain the user id and expiration date.
  • The JWT is stored on a cookie, which is HTTP only, secure, and valid only from the client site domain (is it enough to counter measure csrf attacks?)

The only backdoor I could think of is if the attacker steals the cookie, for which I could add to the JWT payload a unique random value for the user (which is stored on the database), and in the case the user is suspecting that his session was stolen, he could issue a request to reset the unique value, rendering the stolen token useless.

Am I missing any backdoors which could allow an attacker to bypass the authentication easily? Should I use Spring Security instead? I'm afraid I will not be able to achieve the stateless behaviour I currently have...

Thanks!

2

You will be vulnerable to a CSRF attack.

Since you want to be stateless, best option is to use double submit cookie variation. You need to be careful and not to do it naively, please see this question. In short, you will need to tie your CSRF token to a security session:

  1. Generate sufficiently large CSRF token
  2. Include CSRF token inside JWT as one of the claims
  3. Provide CSRF to the client as a result of a successful authentication in a JSON object for example. You will provide cookie containing your JWT in the same step. Cookie can't be read from the client (httpOnly) thus the necessity to provide it in a JSON object or some other format.
  4. On client side store CSRF token in sessionStorage or localStorage and send it to the server on each request that changes state as a header.
  5. On server side validate the value from header and JWT

Your solution for revoking JWT is fine. Be sure to generate new id and issue new token when user changes password.

To minimize possible impact a stolen JWT can have on your application, keep expiration as short as your application can allow it to be.


You can implement a stateless JWT security using Spring Security and should avoid doing it in a REST controller and rolling your own custom implementation. See this as a good starting point. Even though it is for Spring Boot, it can easily be modified so it works with plain Spring.

  • I can't thank you enough for setting me up with this article! I've successfully intergated Spring Security while keeping the jwt token authentication in the app :) – Nadav96 Apr 1 '17 at 16:01
  • And regarding the double submit cookie, I've built a simple filter that does that (and it's working from what I see), is it wrong to build one myself? Should I use prbuilt? The code can be found here. Marking this answer as correct regardless. – Nadav96 Apr 1 '17 at 16:03
  • 1
    Yes, you need to implement your own filter since you are storing csrf token inside JWT and standard solution will not know how to handle it. By looking at the code I see you did a standard double submit. You really nee to tie the csrf to jwt. This means instead of separate cookie, you use jwt cookie used for authentication. Please take a look at linked question and a blackhat article inside it. It will explain why. – Marko Vodopija Apr 1 '17 at 18:33
  • Thank you very much for the suggestion, I decided to keep the seperation between the session cookie (which is HttpOnly), and the csrf cookie, BUT I added a claim in the jwt token that contains a random string, which will serve as the csrf value, and upon receiving request, it will first verify the jwt token intergiy, then proceed to check that the jwt claim is equal to the csrf cookie and the http header value. How does that sound? Are there more repercussions that I can take? I'm generating the csrf value using UUID.randomUUID().toString() , Is that good enough? Can it be brute forced? – Nadav96 Apr 2 '17 at 18:21
  • It is fine approach but your csrf cookie is reduntant. As long as your are comparing it with a value stored in jwt, it will be fine though. UUID.randomUUID() is enough. It has 122bit entropy and uses CSPRNG. – Marko Vodopija Apr 3 '17 at 5:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.