lemmy icon indicating copy to clipboard operation
lemmy copied to clipboard

[Security Issue]: Auth JWT does not have expiration time and is sent in the URL to all requests.

Open samwightt opened this issue 1 year ago • 6 comments

Requirements

  • [X] Is this a bug report? For questions or discussions use https://lemmy.ml/c/lemmy_support
  • [X] Did you check to see if this issue already exists?
  • [X] Is this only a single bug? Do not put multiple bugs in one issue.
  • [X] Is this a backend issue? Use the lemmy-ui repo for UI / frontend issues.

Summary

Lemmy authenticates users with a JWT access token. This JWT does not expire and is only revocable if the user does an event like changing their password. This is insecure and does not follow current best practices for access tokens or for JWTs. To fix this:

  • Add some sort of session revocation mechanism.
  • Move the JWT from a URL param to a header.
  • Give JWTs a short expiration time and have frontends perform a refresh with a refresh token. Have the refresh token rotate on every refresh call.

Steps to Reproduce

Lemmy's API authenticates users using the login operation, which returns a JWT. This JWT is then passed on to all subsequent API calls in the auth param, which is sent in the URL for GET requests. While the JWT uses a good encryption algorithm, it does not contain an expiration time. There are no explicit ways for a user to revoke a particular session or JWT, but all JWTs can be revoked by doing an event like resetting your password. The JWT functions like an access token.

This breaks multiple security best practices around bearer tokens and JWTs, namely:

This is a security vulnerability. If any user JWT is stolen, that JWT will remain active until the user changes their password. Attackers will have access to a user's account for an unlimited amount of time.

Technical Details

No logs.

Version

All Lemmy versions

Lemmy Instance URL

No response

samwightt avatar Jul 05 '23 20:07 samwightt

Also I may be wrong on this, I read the Claims code but there could be something I'm missing here. But on lemmy.blahaj.zone, I'm seeing a JWT sent both in the cookie and as a URL parameter.

samwightt avatar Jul 05 '23 21:07 samwightt

I went a bit deeper on one of your point here: https://github.com/LemmyNet/lemmy/issues/3364

0xAnansi avatar Jul 06 '23 10:07 0xAnansi

JWTs should have a short expiration time (ex. 1 hour)

Doesn't that mean you'd be logged out after one hour?

abhibeckert avatar Jul 10 '23 07:07 abhibeckert

That's what the refresh token is for.

tkroes avatar Jul 10 '23 07:07 tkroes

Please add security label to this issue

NinekoTheCat avatar Jul 10 '23 11:07 NinekoTheCat

That's what the refresh token is for.

Refresh tokens are mainly to reduce server load by avoiding the need to verify the auth token on every request.

While there can be edge cases where they help - I'm of the opinion that's more than offset by increased complexity and risk of a bad/buggy implementation, etc etc. Refresh tokens increase your attack surface.

Having said that, verifying auth tokens once an hour (by checking the refresh token) is certainly better than never verifying them, which seems to be what lemmy is doing now?

And yeah, move the tokens into a HTTP header. Preferably the cookie header - where you can take advantage of the httpOnly and secure flags.

abhibeckert avatar Jul 10 '23 17:07 abhibeckert

https://github.com/LemmyNet/lemmy/pull/3946 moves auth tokens into header/cookie.

Nutomic avatar Sep 28 '23 11:09 Nutomic