MD5PasswordHasher: broken backwards compatibility with empty salt
|Reported by:||Owned by:||nobody|
|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|
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)