Django密码hasher with hash in hash

时间:2014-12-11 23:44:37

标签: python django django-authentication password-hash

也许是一个愚蠢的问题,但如果可能的话,使用用户名作为盐的一部分编写BasePasswordHasher子类的最佳方法是什么?我从头开始重写一个网站,并在php中使用这种方法。问题是在密码哈希中访问用户名。我很乐意解决这个问题,因为很多用户会丢失他们的密码,所以请提前多谢!

PHP代码:

function passHash($login, $pass)
{
    return md5(md5($pass).'salt'.$login);
}

2 个答案:

答案 0 :(得分:4)

正如您所注意到的,这不能仅在密码哈希中完成。密码hasher没有关于用户的信息,只有密码和哈希。我认为你有两种选择。

首先,也许最好的是编写自定义authentication backend。在身份验证后端级别,我们可以访问用户名和原始密码。它看起来像这样

# settings.py
AUTHENTICATION_BACKENDS=(
    'myapp.backends.LegacyBackend',
    'django.contrib.auth.backends.ModelBackend',
)

# myapp.backends
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.utils.encoding import force_bytes
import hashlib

class LegacyBackend(ModelBackend):

    # We only need to override the authenticate method
    def authenticate(self, username=None, password=None, **kwargs):
        # most of this is copied directly from ModelBackend's authenticate method
        UserModel = get_user_model()
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            user = UserModel._default_manager.get_by_natural_key(username)

            # This is the normal route that hands off to the password hasher pipeline
            # but we will sidestep it entirely and verify the password here
            #
            # if user.check_password(password):
            #    return user

            pwhash = hashlib.md5(force_bytes(password)).hexdigest()
            hash = hashlib.md5(force_bytes(pwhash+"salt"+username)).hexdigest()
            if hash == user.password:
                # update the user's password if you want, so you can phase out this backend
                user.set_password(password)
                user.save(update_fields=["password"])
                return user

        except UserModel.DoesNotExist:
            UserModel().set_password(password)

请注意,我还没有测试过此代码,但它应该像宣传的那样工作。此外,您不会与新用户发生冲突,旧用户会将其密码更新为新的哈希算法(默认为PBKDF2 + SHA256?不确定)。

第二个选项是编写一个一次性脚本来修改数据库,以使user.password字段看起来像legacymd5$username+salt$hash。然后,您可以按计划编写自定义密码哈希。

答案 1 :(得分:1)

对于像我一样找到此帖子的任何人,除一件事外,其他所有操作均按预期进行。在Django 2.1上,我发现必须在authenticate方法中添加“ request”作为第一个参数。他们一定在某个时候添加了通过的权限。我默默地使认证失败,不知道为什么。