#18144 closed Bug (fixed)
MD5PasswordHasher: broken backwards compatibility with empty salt
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | contrib.auth | Version: | 1.4 |
Severity: | Release blocker | Keywords: | MD5PasswordHasher check_password salt |
Cc: | slav0nic0@…, carsten.fuchs@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
In our project we stored unsalted MD5 passwords in format: "md5$$<actual md5 hash>".
In Django 1.3 django.contrib.auth.check_password(...) coped well with such format.
In Django 1.4 trying to check such password fails with assertion in django.contrib.auth.hashers.MD5PasswordHasher.encode(...)
Traceback (most recent call last): File "/home/admin/sites/env/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response response = callback(request, *callback_args, **callback_kwargs) File "/home/admin/sites/fxstart-production/source/apps/accounts/decorators.py", line 17, in _wrapped_view return view_func(request, *args, **kwargs) File "/home/admin/sites/fxstart-production/source/apps/dashboard_personal/views.py", line 57, in view_change_password if form.save(): File "/home/admin/sites/fxstart-production/source/apps/dashboard_personal/forms/change_password.py", line 129, in save if not self.account.check_withdraw_password(current_password): File "/home/admin/sites/fxstart-production/source/apps/accounts/models.py", line 184, in check_withdraw_password return check_password(raw_password, self.withdraw_password) File "/home/admin/sites/env/local/lib/python2.7/site-packages/django/contrib/auth/hashers.py", line 45, in check_password is_correct = hasher.verify(password, encoded) File "/home/admin/sites/env/local/lib/python2.7/site-packages/django/contrib/auth/hashers.py", line 319, in verify encoded_2 = self.encode(password, salt) File "/home/admin/sites/env/local/lib/python2.7/site-packages/django/contrib/auth/hashers.py", line 312, in encode assert salt and '$' not in salt AssertionError
As you can see from the code, salt variable is asserted, which means AssertionError is raised every time salt is empty string.
Is this intended behavior? (which means we have to regenerate our password's database or workaround it via replacing hashes like "md5$$<actual md5 hash>" to "<actual md5 hash>" before calling check_password)
Attachments (1)
Change History (23)
comment:1 by , 13 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
comment:2 by , 13 years ago
Resolution: | duplicate |
---|---|
Status: | closed → reopened |
Pardon me, but #17777 is not nearly the same thing I'm talking about here.
And its description and comments doesn't answer my question (and yes, I read it before posting).
I think, you were a bit hasty with bug closing.
What I'm talking about is:
from django.contrib.auth.models import check_password check_password("test", "md5$$098f6bcd4621d373cade4e832627b4f6")
raises AssertionError in Django 1.4, when in Django 1.3 it worked perfectly.
comment:3 by , 13 years ago
Sorry -- #17777 looked suspiciously similar, and I didn't know you had reviewed it first.
comment:4 by , 13 years ago
Has patch: | set |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:6 by , 12 years ago
Cc: | added |
---|
comment:7 by , 12 years ago
Cc: | added |
---|
comment:9 by , 12 years ago
Patch needs improvement: | set |
---|
The patch looks good, but it no longer applies.
comment:10 by , 12 years ago
Resolution: | → fixed |
---|---|
Status: | reopened → closed |
comment:14 by , 12 years ago
Resolution: | fixed |
---|---|
Status: | closed → new |
The same happens with SHA1PasswordHasher, I didn't think necessary to open a new ticket.
I created three pull requests on github
- 1.4.x : https://github.com/django/django/pull/740
- 1.5.x : https://github.com/django/django/pull/742
- master: https://github.com/django/django/pull/741
Regards.
comment:15 by , 12 years ago
Severity: | Normal → Release blocker |
---|
comment:16 by , 12 years ago
I don't think Django ever generated unsalted SHA1 passwords. dahool, can you tell us in which version it did?
comment:17 by , 12 years ago
Django switched to salted sha1 (from unsalted md5) in a49fa746cdc056f0b660f47fbc55aa43fcd54bcc -- I can't see where it did use unsalted sha.
comment:18 by , 12 years ago
Here are the schemes accepted and generated by Django over time.
The new password hashing was added in 1.4.
comment:19 by , 12 years ago
I just realized "unsalted passwords" can mean two things: just a plain SHA1 hash, or sha1$$
followed by a SHA1 hash. The request here is to handle the latter. Historically, Django hasn't checked that the salt isn't empty; now it does, and that's described as a regression here.
Django never generated such hashes and there's no reason to find them in a auth_user table. But that argument also applies to hashes starting with md5$$
, and code was added to support that.
Personally I would have wontfix'd the ticket rather that add code to support dubious schemes that Django never generated. But it would be inconsistent to refuse for SHA1 what was accepted for MD5, so at this point, I'll refrain from closing the ticket or changing its "release blocker" status.
comment:20 by , 12 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
See #17777.