-
-
Notifications
You must be signed in to change notification settings - Fork 859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dont allow reusing password reset token, use normal rate limit #4719
Conversation
let conn = &mut get_conn(pool).await?; | ||
password_reset_request | ||
update(password_reset_request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use delete instead of update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to keep the column so that reset count works. That one is used to limit users to 3 password resets per day. However we could get rid of that and use a normal rate limit instead, eg auth
rate limit which applies to login, register and password reset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per-user rate limits are better
This seems kind of extreme to me. As the code exists, the reset token is only valid for a day anyway. Why not just decrease that time to like an hour, or 15 minutes? These single-use tokens are annoying even when I get them as texts, and they're too quickly invalidated. |
This is not about valid time, but about using the same reset token multiple times. Right now you can do "forgot password" once, then use the reset token to set a new password, and afterwards use the same reset token to change your password again. In fact you can do that an unlimited amount of times which seems completely wrong. |
This is basically the difference between "one-time-use" tokens, HOTP, vs time-based tokens, TOTP. TOTP is much more forgiving and reliable IMO. IMO HOTP are way too pointlessly complicated for our use here, it should be enough to shorten our TOTP time to like 10-15 minutes. |
OTP is literally only to be used once. Quoting Wikipedia:
A TOTP server side implementation that allows token reuse is vulnerable to reply attacks, the very thing that OTPs are designed to prevent. I'm assuming you only brought up TOTP/HOTP for the user experience part, as this is not using that technology, but I don't agree with your stance on that regardless. Both of these implementations however are only secure if token reuse is prevented. The first potential attack that comes to my mind for reusable reset tokens is shared computers, when someone resets their lemmy password, then logs out of all of their sessions, but doesn't clear their browsing history. The next person using that computer will be able to find the reset url in the browser history and compromise the account. |
let conn = &mut get_conn(pool).await?; | ||
password_reset_request | ||
update(password_reset_request) | ||
.filter(valid.eq(true)) | ||
.filter(token.eq(token_)) | ||
.filter(published.gt(now.into_sql::<Timestamptz>() - 1.days())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only line you need to change. Change this to a shorter time span, and none of this is necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thats not it, having the reset token valid for a day is fine in case you dont receive it immediately. But it should be possible to reuse the same one multiple times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, seems a bit overkill to me still, but its fine.
This is not about TOTP (2 facor auth), but about the password reset at |
0bfedab
to
d3615d6
Compare
Ive changed it now to use the normal rate limit, so |
let conn = &mut get_conn(pool).await?; | ||
password_reset_request | ||
.filter(local_user_id.eq(user_id)) | ||
delete(password_reset_request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surprised that delete works with .get_result
, but you verified it below in the tests anyway.
With the current code it is possible to reuse the same reset token multiple times.