Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#32130 closed Bug (fixed)

Password reset token incompatibility.

Reported by: Gordon Wrigley Owned by: Mariusz Felisiak
Component: contrib.auth Version: 3.1
Severity: Release blocker Keywords:
Cc: Adam Johnson, Hasan Ramezani Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

As noted here https://docs.djangoproject.com/en/3.1/releases/3.1/#django-contrib-auth the hashing for password reset tokens has changed between 3.0 and 3.1 and work has been done to ensure existing tokens will still work (at least until 4.0).

However the encoding of the token creation time has also changed. Specifically from days since 1/1/01 to seconds since 1/1/01. And it appears no work has been done to support tokens with the older values. So a token generated on Oct 1, 2020 will come through as 7213 days which will then get interpreted as 7213 seconds, aka 2am Jan 1, 2001.

So while exiting tokens in the wild will pass crypto validation they will all show as expired if your PASSWORD_RESET_TIMEOUT is less than ~20 years.

The code base I'm working on uses these tokens (perhaps unwisely) in some email links that are expected to have a 3 month lifetime and an upgrade from 3.0 to 3.1 looks likely to render all the tokens in the wild expired which is suboptimal.

Change History (13)

comment:1 Changed 3 years ago by Adam Johnson

This seems like an oversight. Would it make sense to reinterpret tokens with a timeout less than some small-in-seconds but large-in-days cutoff, such as 3600 * 365, as days instead of seconds?

comment:2 Changed 3 years ago by Adam Johnson

Cc: Adam Johnson added

comment:3 Changed 3 years ago by Gordon Wrigley

We've been discussing using patchy to do something to that effect.

With free code access you can easily tell because the prefix is 3 characters in the old scheme and 6 in the other so you could switch off that.

If you were to switch off value anything in the 10k (~27*365) - 600m(~19*365*60*60) range should be a safe cutoff.

comment:4 Changed 3 years ago by Mariusz Felisiak

Great catch, we missed this. However, I'm not sure what we can do, any heuristic will be clunky, IMO. 1 second, 1 day, 300k seconds, or 300k days are all valid.

comment:5 Changed 3 years ago by Adam Johnson

It’s seconds/days since January 2001, so I don’t think it’s clunky... I doubt anyone is running an app with the clock set between 2001 and 2002 for example.

comment:6 Changed 3 years ago by Gordon Wrigley

I think the prefix length might be a better check, it's totally unambiguous

comment:7 Changed 3 years ago by Mariusz Felisiak

Cc: Hasan Ramezani added
Component: Uncategorizedcontrib.auth
Owner: changed from nobody to Mariusz Felisiak
Severity: NormalRelease blocker
Status: newassigned
Summary: 3.0 -> 3.1 password token incompatibility.Password reset token incompatibility.
Triage Stage: UnreviewedAccepted
Type: UncategorizedBug

I think the prefix length might be a better check, it's totally unambiguous

Ahh, yes. That's bulletproof, thanks!

Regression in 45304e444e0d780ceeb5fc03e6761569dfe17ab2.

comment:8 Changed 3 years ago by Mariusz Felisiak

Has patch: set

comment:9 Changed 3 years ago by Carlton Gibson

Triage Stage: AcceptedReady for checkin

comment:10 Changed 3 years ago by GitHub <noreply@…>

Resolution: fixed
Status: assignedclosed

In 3418092:

Fixed #32130 -- Fixed pre-Django 3.1 password reset tokens validation.

Thanks Gordon Wrigley for the report and implementation idea.

Regression in 226ebb17290b604ef29e82fb5c1fbac3594ac163.

comment:11 Changed 3 years ago by Mariusz Felisiak <felisiak.mariusz@…>

In 767e06b5:

[3.1.x] Fixed #32130 -- Fixed pre-Django 3.1 password reset tokens validation.

Thanks Gordon Wrigley for the report and implementation idea.

Regression in 226ebb17290b604ef29e82fb5c1fbac3594ac163.
Backport of 34180922380cf41cd684f846ecf00f92eb289bcf from master

comment:12 Changed 3 years ago by Adam Johnson

Great work on a quick fix Mariusz!

comment:13 Changed 3 years ago by Gordon Wrigley

Yes, thank you for the quick response.

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