无法使用自定义PASSWORD_HASHERS进行身份验证 [英] Can't authenticate with custom PASSWORD_HASHERS

查看:237
本文介绍了无法使用自定义PASSWORD_HASHERS进行身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我使用的是一个特定的哈希密码算法,所以我不得不写道:

我正在使用php将一个网站迁移到Django框架。 / p>

 #settings.py 
PASSWORD_HASHERS =(
'django.contrib.auth.hashers.PBKDF2PasswordHasher'
'project.hashers.SHA1ProjPasswordHasher',#这是我的
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
...

和:

  #hashers .py 

import hashlib

from django.contrib.auth.hashers import(BasePasswordHasher,mask_hash)
from django.utils.datastructures import SortedDict
from django.utils.encoding import force_bytes
from django.utils.crypto import constant_time_compare
from django.utils.translation import ugettext_noop as _


class SHA1ProjPasswordHasher(BasePasswordHasher ):

特殊的雪花算法第一个版本。
php code:$ pass = substr(sha1(trim($ _ POST ['password'])),0,8);

algorithm =unsalted_and_trimmed_sha1

def salt(self):
return''

def encode(self,密码,salt):
return hashlib.sha1(force_bytes(salt + password))。hexdigest()[:8]

def verify(self,password,encoded):
encoded_2 = self.encode(password,'')
return constant_time_compare(encoded,encoded_2)

def safe_summary(self,encoded):
return SortedDict([
(_('algorithm'),self.algorithm),
(_('hash'),mask_hash(encoded,show = 3)),
])

PBKDF2PasswordHasher 是第一个:

 >>> from django.contrib.auth import authenticate 
>>> u = authenticate(username ='root' password ='test')
>>> u.password
u'pbkdf2_sha256 $ 10000 $ EX8BcgPFjygx $ HvB6NmZ7uX1rWOOPbHRKd8GLYD3cAsQ tlprXUq1KGMk ='
>>> exit()

然后我把我的 SHA1ProjPasswordHasher 首先,第一认证工作很好。哈希已更改:

 >>>来自django.contrib.auth import authenticate 
>>> u = authenticate(username ='root',password ='test')
>>> u.password
'a94a8fe5'
>>> exit()

第二个身份验证失败。无法使用新的哈希进行身份验证。

 >>>来自django.contrib.auth import authenticate 
>>> u = authenticate(username ='root',password ='test')
>>> u.password
追溯(最近的最后一次呼叫):
文件< console>,第1行,< module>
AttributeError:'NoneType'对象没有属性'password'

可能是什么问题?谢谢。






更新:好的,问题变得更加清晰。当我从这里删除切片时:

 返回hashlib.sha1(force_bytes(salt + password))hexdigest()[:8 ] 

一切正常。我不能为什么..

解决方案

只有没有限制的md5哈希值不能包含美元符号:

 #django / contrib / auth / hashers.py 

def identify_hasher(编码):

返回加载的密码哈希的一个实例

通过检查编码的哈希标识哈希算法,并调用
get_hasher()返回hasher,如果
算法不能引发ValueError

如果len(编码)== 32和'$'未编码:
algorithm ='unsalted_md5'
否则:
algorithm = encoded.split('$',1)[0]
返回get_hasher(算法)

所以最好的方法是将当前的密码哈希转换为格式: alg $ salt $ hash

 类SHA1ProjPasswordHasher(BasePasswordHasher):

特殊的雪花算法从第一个版本
php code:$ pass = substr(sha1(trim($ _ POST ['password'])),0,8);

algorithm =unsalted_and_trimmed_sha1

def salt(self):
return''

def encode(self,密码,盐):
assert密码
assert'$'不在盐
哈希= hashlib.sha1(强制字符(salt +密码))hexdigest()[:8]
返回%s $%s $%s%(self.algorithm,salt,hash)

def verify(self,password,encoded):
algorithm,salt,hash = encoding.split('$',2)
assert algorithm == self.algorithm
encoded_2 = self.encode(password,salt)
return constant_time_compare(encoded,encoded_2)

def safe_summary(self,encoded):
算法,salt,hash = encoded.split('$',2)
assert algorithm == self.algorithm
return SortedDict [
(_('algorithm'),algorithm),
(_('salt'),mask_hash(salt,show = 2)),
(_('hash' mask_hash (哈希)),
])

 >>>来自django.contrib.auth import authenticate 
>>> x = authenticate(username ='root',password ='test')
>>> x
< User:root>
>>> x.password
u'unsalted_and_trimmed_sha1 $$ a94a8fe5'


I am working on the migration of one website with php to Django framework.

There is used to a specific hash passwords algorithm, so I had to write:

#settings.py
PASSWORD_HASHERS = (
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'project.hashers.SHA1ProjPasswordHasher',        # that's mine
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
 ...
)

and:

#hashers.py

import hashlib

from django.contrib.auth.hashers import (BasePasswordHasher, mask_hash)
from django.utils.datastructures import SortedDict
from django.utils.encoding import force_bytes
from django.utils.crypto import constant_time_compare
from django.utils.translation import ugettext_noop as _


class SHA1ProjPasswordHasher(BasePasswordHasher):
    """
    Special snowflake algorithm from the first version.
    php code: $pass=substr(sha1(trim($_POST['password'])),0,8);
    """
    algorithm = "unsalted_and_trimmed_sha1"

    def salt(self):
        return ''

    def encode(self, password, salt):
        return hashlib.sha1(force_bytes(salt + password)).hexdigest()[:8]

    def verify(self, password, encoded):
        encoded_2 = self.encode(password, '')
        return constant_time_compare(encoded, encoded_2)

    def safe_summary(self, encoded):
        return SortedDict([
            (_('algorithm'), self.algorithm),
            (_('hash'), mask_hash(encoded, show=3)),
            ])

It's works well when PBKDF2PasswordHasher is first:

>>> from django.contrib.auth import authenticate
>>> u = authenticate(username='root', password='test')
>>> u.password
u'pbkdf2_sha256$10000$EX8BcgPFjygx$HvB6NmZ7uX1rWOOPbHRKd8GLYD3cAsQtlprXUq1KGMk='
>>> exit()

Then I put my SHA1ProjPasswordHasher on the first place, first authentication works great. The hash was changed.:

>>> from django.contrib.auth import authenticate
>>> u = authenticate(username='root', password='test')
>>> u.password
'a94a8fe5'
>>> exit()

Second authentication is failed. Can't authenticate with new hash.

>>> from django.contrib.auth import authenticate
>>> u = authenticate(username='root', password='test')
>>> u.password
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'password'

What could be the problem? Thanks.


UPDATE: Ok, the problem became more clear. When I remove slice from here:

return hashlib.sha1(force_bytes(salt + password)).hexdigest()[:8]

everything working fine. I can't get why..

解决方案

Only unsalted md5 hashes can not include a dollar sign:

# django/contrib/auth/hashers.py

def identify_hasher(encoded):
    """
    Returns an instance of a loaded password hasher.

    Identifies hasher algorithm by examining encoded hash, and calls
    get_hasher() to return hasher. Raises ValueError if
    algorithm cannot be identified, or if hasher is not loaded.
    """
    if len(encoded) == 32 and '$' not in encoded:
        algorithm = 'unsalted_md5'
    else:
        algorithm = encoded.split('$', 1)[0]
    return get_hasher(algorithm)

So the best way is convert the current password hashes to the format: alg$salt$hash

class SHA1ProjPasswordHasher(BasePasswordHasher):
    """
    Special snowflake algorithm from the first version.
    php code: $pass=substr(sha1(trim($_POST['password'])),0,8);
    """
    algorithm = "unsalted_and_trimmed_sha1"

    def salt(self):
        return ''

    def encode(self, password, salt):
        assert password
        assert '$' not in salt
        hash = hashlib.sha1(force_bytes(salt + password)).hexdigest()[:8]
        return "%s$%s$%s" % (self.algorithm, salt, hash)

    def verify(self, password, encoded):
        algorithm, salt, hash = encoded.split('$', 2)
        assert algorithm == self.algorithm
        encoded_2 = self.encode(password, salt)
        return constant_time_compare(encoded, encoded_2)

    def safe_summary(self, encoded):
        algorithm, salt, hash = encoded.split('$', 2)
        assert algorithm == self.algorithm
        return SortedDict([
            (_('algorithm'), algorithm),
            (_('salt'), mask_hash(salt, show=2)),
            (_('hash'), mask_hash(hash)),
            ])

.

>>> from django.contrib.auth import authenticate
>>> x = authenticate(username='root', password='test')
>>> x
<User: root>
>>> x.password
u'unsalted_and_trimmed_sha1$$a94a8fe5'

这篇关于无法使用自定义PASSWORD_HASHERS进行身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆