问题描述
我使用的是一个特定的哈希密码算法,所以我不得不写道:
我正在使用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进行身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!