Logging in from one browser logs me out from other browsers (after any change in PBKDF2PasswordHasher.iterations)

112 views
Skip to first unread message

אורי

unread,
Sep 2, 2020, 10:56:13 PM9/2/20
to Django developers (Contributions to Django itself)
Django developers,

I would like to reopen #31970. In short, the problem is - if a user is logged in with more than one browser, and when we upgrade Django to any version which PBKDF2PasswordHasher.iterations changes (which is any new version), and then the user logs in again - this logs them out from all other browsers. I think this is a bug.

I found out that this can be avoided by changing def must_update, for example if you change it to something like:

def must_update(self, encoded):
# Update the stored password only if the iterations diff is at least 250,000.
algorithm, iterations, salt, hash = encoded.split('$', 3)
iterations_diff = abs(self.iterations - int(iterations))
return ((int(iterations) != self.iterations) and (iterations_diff >= 250000))
Or even simply:

def must_update(self, encoded):
return False

Florian Apolloner

unread,
Sep 3, 2020, 3:29:13 AM9/3/20
to Django developers (Contributions to Django itself)
I do not think there is anything to reopen because it works as designed. Password changes cause other browser sessions to be terminated because the session auth hash no longer matches.  You can use a custom user model and override `get_session_auth_hash` but the defaults won't change, sorry.

Adam Johnson

unread,
Sep 3, 2020, 3:38:17 AM9/3/20
to django-d...@googlegroups.com
I agree with Florian.

The occasional forced logout is probably fine. If you care about this enough Uri, you could write a blog post documenting your patch and how to use it when upgrading Django.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/87b16804-3da2-46b7-8ff5-466cd2f38aa2n%40googlegroups.com.


--
Adam

Shai Berger

unread,
Sep 3, 2020, 4:23:25 AM9/3/20
to django-d...@googlegroups.com
Hi Uri and all,

On Thu, 3 Sep 2020 08:37:42 +0100
Adam Johnson <m...@adamj.eu> wrote:

> I agree with Florian.
>

Me too.

> The occasional forced logout is probably fine. If you care about this
> enough Uri, you could write a blog post documenting your patch and
> how to use it when upgrading Django.
>

But:

> On Thu, 3 Sep 2020 at 08:29, Florian Apolloner <f.apo...@gmail.com>
> wrote:
> > On Thursday, September 3, 2020 at 4:56:13 AM UTC+2 Uri wrote:
> >>
> >> I found out that this can be avoided by changing *def
> >> must_update*, for example if you change it to something like:
> >>
> >> def must_update(self, encoded):
> >> # Update the stored password only if the iterations diff is at least 250,000.
> >> algorithm, iterations, salt, hash = encoded.split('$', 3)
> >> iterations_diff = abs(self.iterations - int(iterations))
> >> return ((int(iterations) != self.iterations) and (iterations_diff >= 250000))
> >>
> >> Or even simply:
> >>
> >> def must_update(self, encoded):
> >> return False
> >>

Please be aware that this is a security issue. The passwords are
encrypted as protection for the case that they fall into the hands of
an attacker, but for this protection to be effective, it must stay hard
and costly to brute-force them. The number of iterations is enlarged in
order to keep this cost up with the improvements of available hardware.
If you intend to keep a user's password un-updated for many years, it's
almost as bad as keeping it in plaintext -- in 10-15 years, we'd expect
the number of iterations in current Django to be grossly insufficient.

HTH,
Shai.

אורי

unread,
Sep 3, 2020, 4:49:02 AM9/3/20
to Django developers (Contributions to Django itself)
Hi,

On Thu, Sep 3, 2020 at 11:23 AM Shai Berger <sh...@platonix.com> wrote:

Please be aware that this is a security issue. The passwords are
encrypted as protection for the case that they fall into the hands of
an attacker, but for this protection to be effective, it must stay hard
and costly to brute-force them. The number of iterations is enlarged in
order to keep this cost up with the improvements of available hardware.
If you intend to keep a user's password un-updated for many years, it's
almost as bad as keeping it in plaintext -- in 10-15 years, we'd expect
the number of iterations in current Django to be grossly insufficient.

I don't intend to keep the settings of now for 10-15 years. But since I launched Speedy Net in Django 1.11 in production 13 months ago, I upgraded to 2.0, 2.1, 2.2, 3.0 and now 3.1. These are 5 major version upgrades in 13 months. I don't see a reason why the number of iterations should have changed 5 times in 13 months. Even if I would upgrade Django every 8 months, I prefer to keep the number of iterations and change it every 2-3 years, if this logs out users. I'm not sure if I'll write a blog post, but you can see our patch on GitHub:


I wish I knew about this issue before and then I would have patched something like this before, before causing this to change 5 times in production.

אורי.

Tom Forbes

unread,
Sep 3, 2020, 4:57:55 AM9/3/20
to django-d...@googlegroups.com
You might have a point regarding the frequency of bumping the PBKDF iteration setting. Is bumping it 5 times in 13 months really required? On the other hand you might want to consider staying on the LTS releases and avoid issues such as this, and the issue you’re describing is quite niche.

However, I would say that based on your previous posts to this mailing lists around authentication that you are definitely in need of some form of federated login/SSO for your several web properties. That would certainly alleviate this issue and some of the other problems you’ve reported here.

Tom 

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.

אורי

unread,
Sep 3, 2020, 4:59:12 AM9/3/20
to Django developers (Contributions to Django itself)
Hi,

To conclude, I think it would be better to change the number of iterations not every 8 months, but every 2 years (with a new LTS release).

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.

אורי

unread,
Sep 3, 2020, 5:04:06 AM9/3/20
to Django developers (Contributions to Django itself)
On Thu, Sep 3, 2020 at 11:57 AM Tom Forbes <t...@tomforb.es> wrote:
You might have a point regarding the frequency of bumping the PBKDF iteration setting. Is bumping it 5 times in 13 months really required? On the other hand you might want to consider staying on the LTS releases and avoid issues such as this, and the issue you’re describing is quite niche.

However, I would say that based on your previous posts to this mailing lists around authentication that you are definitely in need of some form of federated login/SSO for your several web properties. That would certainly alleviate this issue and some of the other problems you’ve reported here.

Thank you for your suggestions. I was not aware that upgrading to non-LTS releases will log out users. It's good to know now.

Carlton Gibson

unread,
Sep 3, 2020, 5:07:13 AM9/3/20
to Django developers (Contributions to Django itself)

On 3 Sep 2020, at 10:57, Tom Forbes <t...@tomforb.es> wrote:

You might have a point regarding the frequency of bumping the PBKDF iteration setting. Is bumping it 5 times in 13 months really required?

It was more like 40 months. 

For 1.11: May 20, 2016

For 3.1: Sep 12, 2019

> On the other hand you might want to consider staying on the LTS releases and avoid issues such as this...

The issue came up because of starting on the LTS and then wanting the new features… — You’re on the latest version now Uri, which is the good place to be (!) — so it’s once in 8 months you’re going to hit this.

Adam Johnson

unread,
Sep 3, 2020, 5:10:39 AM9/3/20
to django-d...@googlegroups.com
You could also move to use the Argon2 hasher, which does not have any chagnes between versions to log out users: https://docs.djangoproject.com/en/3.0/topics/auth/passwords/#using-argon2-with-django

It's also considered more secure. As the docs say:

Argon2 is not the default for Django because it requires a third-party library. The Password Hashing Competition panel, however, recommends immediate use of Argon2 rather than the other algorithms supported by Django.

Requiring a third-party library is less controversial these days compared to when we added the Argon2 hasher. Perhaps we could make it the default for new projects now, rather than changing our frequency of increasing PBKDF2 iterations.



--
Adam

Florian Apolloner

unread,
Sep 3, 2020, 9:04:04 AM9/3/20
to Django developers (Contributions to Django itself)
On Thursday, September 3, 2020 at 11:10:39 AM UTC+2 Adam Johnson wrote:
You could also move to use the Argon2 hasher, which does not have any chagnes between versions to log out users: https://docs.djangoproject.com/en/3.0/topics/auth/passwords/#using-argon2-with-django

Or a custom subclass of a PBKDF2 which sets the wanted iteration count… I think the defaults in Django are fine :)
Reply all
Reply to author
Forward
0 new messages