40

I have implemented a stateless auth over HTTP in Laravel, using JWTs.

  1. I send my username/password from the frontend.
  2. Server authenticates user, sends back a signed JWT with an expiry time.
    • I'm using the HS512 algorithm to sign with a private key (only available to the server).
  3. Frontend stores the token for future requests.
  4. Frontend sends next request with the token included.
  5. Server verifies that the token is valid, and not expired, and lets the action continue if yes to both.
  6. When the token expires server sends a 'logged-out' message.

All these communications happen over HTTPS.

So I can see that this is secure from these points:

  • Attackers can't sniff traffic and steal the JWT token because of HTTPS.
  • Attackers can't generate and send any odd token because server verifies the signature using its private key.
  • Attackers can't modify which user (and hence, the role+permissions of the requester) is making the request, because that's part of the sub claim in the token.

But, I have two questions:

  1. What if there is a virus on the user's computer or mobile, and it stole a valid token from RAM or from the browser. It can then send more requests, and they will be accepted. Is there any way at all to protect against this?
  2. Is there another way to attack this system that I am not seeing?
TN.
  • 153
  • 5
Aditya M P
  • 642
  • 1
  • 6
  • 11

4 Answers4

30

The jti claim as described here is an optional mechanism for preventing further replay attacks. From the spec:

4.1.7. "jti" (JWT ID) Claim

The "jti" (JWT ID) claim provides a unique identifier for the JWT. The identifier value MUST be assigned in a manner that ensures that there is a negligible probability that the same value will be accidentally assigned to a different data object; if the application uses multiple issuers, collisions MUST be prevented among values produced by different issuers as well. The "jti" claim can be used to prevent the JWT from being replayed. The "jti" value is a case- sensitive string. Use of this claim is OPTIONAL.

This does ultimately make your server stateful, but it prevents against unlimited replays if you detect anomalous behavior, or if a user reports suspicious activity. Consider the following scenario.

  1. A user logs in. Your server generates a JWT, and stores the signature as well as some metadata (the user id and the type of client making the request, perhaps, and the jti).
  2. User reports suspicious behavior.
  3. The application "signs out" the user of all devices by deleting all JWTs in the backend store attached to that user. Now the application can say "I know you've got a valid signature, but I'm not accepting it because I didn't create it."
    • If your metadata is precise enough, you can use the jti plus additional information to, say, only sign the user out of given devices.

As mentioned above, this does inevitably make your server stateful. This also doesn't outright prevent replay attacks, but it can shut down further such attacks after one has been detected.

An alternative/additional method CAN outright prevent replay attacks to some degree, at the risk of potential inconvenience to the user. Make the user's IP address part of the claim AND stored metadata upon login, and validate that the IP using the JWT is the one you expect. This can be frustrating for a user that say, both works from home and a coffee shop, but it might be an acceptable requirement for high-security applications.

bretmattingly
  • 435
  • 4
  • 5
5

If there is code executing in the same context of your web application, whether it was part of a XSS attack in the browser, or some malware/virus on the users machine, it would be difficult (impossible?) to differentiate those requests from your own.

If the attacker has access to the computer, they could also just steal the data from your applications normal requests to your server.

Potentially, you could some server side intrusion detection style analysis: e.g. check for a high number of requests or item counts; enforce some custom referrer scheme where you know which components of you web application make data requests. Then maybe trigger a reauthentication when you detect anomalous behavior? You would also need a server side way to expire your JWT above the exp embedded in the JWT.

Kevin Hakanson
  • 491
  • 1
  • 5
  • 13
  • Thanks, I particularly like the idea of encrypting, say, the 'directive' name within the token (in case of angularJS) and checking against a list of allowed directives etc on the server. But, this would mean encryption algorithms working on the client side, and that would mean the key being exposed on the client side... still need to think of a solution. – Aditya M P Nov 27 '14 at 10:48
  • There is something called jti (http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#jtiDef) which is meant to secure against replay attacks, but I have no clue how that would work... – jao Nov 27 '14 at 22:21
3

JWT is a bearer token by design so the client who has it can use it multiple times. So if you want to keep your session management stateless thats a tradeoff you will have to make. This article about stateful vs stateless session management highlights the differences very well.

If you want to keep a higher level security then you need to use a different approach for example using signature schemes or letting HTTPS handle it via TLS.

1

Why not have a date time as payload and expiry? You don't need to change the payload and application logic can expire the token. Or use a new secret based on a leaf nature (akin to DUKPT) so a new token request invalidates the old one.

ThoriumBR
  • 50,648
  • 13
  • 127
  • 142
TheBB
  • 11
  • 1