Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#28248 closed Bug (invalid)

Password resets are allowed for 1 day longer than PASSWORD_RESET_TIMEOUT_DAYS

Reported by: Nick Zaccardi Owned by: nobody
Component: contrib.auth Version: 2.0
Severity: Release blocker Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

An improper comparison (> rather than >=) in the password reset token checking, allows password reset tokens to be used one day longer than expected.

Change History (12)

comment:1 by Tim Graham, 7 years ago

Has patch: set

comment:2 by Tim Graham <timograham@…>, 7 years ago

Resolution: fixed
Status: newclosed

In 95993a8:

Fixed #28248 -- Fixed password reset tokens being valid for 1 day longer than PASSWORD_RESET_TIMEOUT_DAYS.

comment:3 by Luke Plant, 7 years ago

Resolution: fixed
Status: closednew

I believe this change is incorrect and should be reverted, according to a common sense interpretation of the setting.

The code rounds all timestamps to midnight (server time) providing a resolution of only 1 day. So if you generate a links 5 minutes before midnight and try to use it 6 minutes later, that counts as 1 day. With the current code, if you set the timeout setting to 1 day, such a link would be rejected.

In other words, new code interprets timeout of 1 day as "up to one day, could be almost zero". The old way interpreted as "at least 1 day, could be up to 2". I think the old way was better, much less likely to be an accidental usability issue. There is virtually no security concern with being too generous here (see my latest post on django-devs on related issue).

comment:4 by Claude Paroz, 7 years ago

Severity: NormalRelease blocker
Version: 1.112.0

comment:5 by Tim Graham <timograham@…>, 7 years ago

Resolution: fixed
Status: newclosed

In 67a6ba39:

Reverted "Fixed #28248 -- Fixed password reset tokens being valid for 1 day longer than PASSWORD_RESET_TIMEOUT_DAYS."

This reverts commit 95993a89ce6ca5f5e26b1c22b65c57dcb8c005e9.

comment:6 by Tim Graham <timograham@…>, 7 years ago

In e241b4e7:

[2.0.x] Reverted "Fixed #28248 -- Fixed password reset tokens being valid for 1 day longer than PASSWORD_RESET_TIMEOUT_DAYS."

This reverts commit 95993a89ce6ca5f5e26b1c22b65c57dcb8c005e9.

Backport of 67a6ba391bbcf1a4c6bb0c42cb17e4fc0530f6d2 from master

comment:7 by Tim Graham, 7 years ago

Resolution: fixedinvalid

comment:8 by Claude Paroz, 7 years ago

I think it would be great to add at least some part of Luke's comment in a code comment to prevent further reports about this issue.

comment:9 by Tim Graham, 7 years ago

PR to clarify the docs and code comment.

comment:10 by Nick Zaccardi, 7 years ago

Sorry to be a moment late to respond. I think the reversion is the correct action for the 99+% and I support that direction. In fact, the fix I originally supplied does have the rounding bug. My apologies for that, I misunderstood the way the rounding work.

I do want to explain why this doesn't meet the 1% of use cases. When I originally reported this I was working on a password reset feature in a different app (a large corporate financial application) which has very specific policies on passwords, password resets, and the validity time of both. From a contractual perspective (regardless of user experience) >24hr link would be a break in policy or worse a violation of contractual obligation to implement a <24hr link. For most up to 2 days is fine, for some, regardless of the real-life implications of the policy, it is a big deal.

All that to say, why does this get rounded in the first place? why not just use:

validity_time = now() + {{ reset_timedelta }}

if validity_time < now():
    // is expired 

Thanks for all you folks do!

in reply to:  10 comment:11 by Luke Plant, 7 years ago

Replying to Nick Zaccardi:

I do want to explain why this doesn't meet the 1% of use cases. When I originally reported this I was working on a password reset feature in a different app (a large corporate financial application) which has very specific policies on passwords, password resets, and the validity time of both. From a contractual perspective (regardless of user experience) >24hr link would be a break in policy or worse a violation of contractual obligation to implement a <24hr link. For most up to 2 days is fine, for some, regardless of the real-life implications of the policy, it is a big deal.

Thanks for filling in these background details. It is unfortunate that sometimes these policies exist which actually don't apply (for reasons that I described here - https://groups.google.com/d/msg/django-developers/65iOQunvkPY/pP5mF-44AQAJ )

However, your experience is still a significant data point in favour of the feature being asked for in that thread ( https://groups.google.com/forum/#!topic/django-developers/65iOQunvkPY ), namely, supporting a timeout of less than one day. Please do feel free to jump into that thread and add your 2 cents - we have to be pragmatic about complying with these kinds of regulations.

All that to say, why does this get rounded in the first place? why not just use:

It is mainly rounded to make the timestamp shorter (we only need to store a number of days, not seconds), which has an impact on the length of URL generated. That may sound like a dubious argument, but that was the initial rationale I believe! With some email clients that like to truncate URLs etc., it can make a difference. Maybe things are better these days...

comment:12 by GitHub <noreply@…>, 7 years ago

In 0edff210:

Refs #28248 -- Clarified the precision of PASSWORD_RESET_TIMEOUT_DAYS.

Note: See TracTickets for help on using tickets.
Back to Top