Django密码存储策略分析
一、源码分析
Django发布的1.4版本中包含了一些安全方面的重要提升。其中一个是使用PBKDF2密码加密算法代替了SHA1。另外一个特性是你可以添加自己的密码加密方法。
Django会使用你提供的第一个密码加密方法(在你的 setting.py 文件里要至少有一个方法)
PASSWORD_HASHERS=[ 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ]
我们先一睹自带的PBKDF2PasswordHasher加密方式。
classBasePasswordHasher(object):
"""
Abstractbaseclassforpasswordhashers
Whencreatingyourownhasher,youneedtooverridealgorithm,
verify(),encode()andsafe_summary().
PasswordHasherobjectsareimmutable.
"""
algorithm=None
library=None
def_load_library(self):
ifself.libraryisnotNone:
ifisinstance(self.library,(tuple,list)):
name,mod_path=self.library
else:
name=mod_path=self.library
try:
module=importlib.import_module(mod_path)
exceptImportError:
raiseValueError("Couldn'tload%spasswordalgorithm"
"library"%name)
returnmodule
raiseValueError("Hasher'%s'doesn'tspecifyalibraryattribute"%
self.__class__)
defsalt(self):
"""
Generatesacryptographicallysecurenoncesaltinascii
"""
returnget_random_string()
defverify(self,password,encoded):
"""
Checksifthegivenpasswordiscorrect
"""
raiseNotImplementedError()
defencode(self,password,salt):
"""
Createsanencodeddatabasevalue
Theresultisnormallyformattedas"algorithm$salt$hash"and
mustbefewerthan128characters.
"""
raiseNotImplementedError()
defsafe_summary(self,encoded):
"""
Returnsasummaryofsafevalues
Theresultisadictionaryandwillbeusedwherethepasswordfield
mustbedisplayedtoconstructasaferepresentationofthepassword.
"""
raiseNotImplementedError()
classPBKDF2PasswordHasher(BasePasswordHasher):
"""
SecurepasswordhashingusingthePBKDF2algorithm(recommended)
ConfiguredtousePBKDF2+HMAC+SHA256.
Theresultisa64bytebinarystring.Iterationsmaybechanged
safelybutyoumustrenamethealgorithmifyouchangeSHA256.
"""
algorithm="pbkdf2_sha256"
iterations=36000
digest=hashlib.sha256
defencode(self,password,salt,iterations=None):
assertpasswordisnotNone
assertsaltand'$'notinsalt
ifnotiterations:
iterations=self.iterations
hash=pbkdf2(password,salt,iterations,digest=self.digest)
hash=base64.b64encode(hash).decode('ascii').strip()
return"%s$%d$%s$%s"%(self.algorithm,iterations,salt,hash)
defverify(self,password,encoded):
algorithm,iterations,salt,hash=encoded.split('$',3)
assertalgorithm==self.algorithm
encoded_2=self.encode(password,salt,int(iterations))
returnconstant_time_compare(encoded,encoded_2)
defsafe_summary(self,encoded):
algorithm,iterations,salt,hash=encoded.split('$',3)
assertalgorithm==self.algorithm
returnOrderedDict([
(_('algorithm'),algorithm),
(_('iterations'),iterations),
(_('salt'),mask_hash(salt)),
(_('hash'),mask_hash(hash)),
])
defmust_update(self,encoded):
algorithm,iterations,salt,hash=encoded.split('$',3)
returnint(iterations)!=self.iterations
defharden_runtime(self,password,encoded):
algorithm,iterations,salt,hash=encoded.split('$',3)
extra_iterations=self.iterations-int(iterations)
ifextra_iterations>0:
self.encode(password,salt,extra_iterations)
正如你看到那样,你必须继承自BasePasswordHasher,并且重写 verify() , encode() 以及 safe_summary() 方法。
Django是使用PBKDF2算法与36,000次的迭代使得它不那么容易被暴力破解法轻易攻破。密码用下面的格式储存:
algorithm$numberofiterations$salt$passwordhash”
例:pbkdf2_sha256$36000$Lx7auRCc8FUI$eG9lX66cKFTos9sEcihhiSCjI6uqbr9ZrO+Iq3H9xDU=
二、自定义密码加密方法
1、在settings.py中加入自定义的加密算法:
PASSWORD_HASHERS=[ 'myproject.hashers.MyMD5PasswordHasher', 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ]
2、再来看MyMD5PasswordHasher,这个是我自定义的加密方式,就是基本的md5,而django的MD5PasswordHasher是加盐的:
fromdjango.contrib.auth.hashersimportBasePasswordHasher,MD5PasswordHasher
fromdjango.contrib.auth.hashersimportmask_hash
importhashlib
classMyMD5PasswordHasher(MD5PasswordHasher):
algorithm="mymd5"
defencode(self,password,salt):
assertpasswordisnotNone
hash=hashlib.md5(password).hexdigest().upper()
returnhash
defverify(self,password,encoded):
encoded_2=self.encode(password,'')
returnencoded.upper()==encoded_2.upper()
defsafe_summary(self,encoded):
returnOrderedDict([
(_('algorithm'),algorithm),
(_('salt'),''),
(_('hash'),mask_hash(hash)),
])
之后可以在数据库中看到,密码确实使用了自定义的加密方式。
3、修改认证方式
AUTHENTICATION_BACKENDS=( 'framework.mybackend.MyBackend',#新加 'django.contrib.auth.backends.ModelBackend', 'guardian.backends.ObjectPermissionBackend', )
4、再来看自定义的认证方式
framework.mybackend.py: importhashlib fromproimportmodels fromdjango.contrib.auth.backendsimportModelBackend classMyBackend(ModelBackend): defauthenticate(self,username=None,password=None): try: user=models.M_User.objects.get(username=username) printuser exceptException: print'nouser' returnNone ifhashlib.md5(password).hexdigest().upper()==user.password: returnuser returnNone defget_user(self,user_id): try: returnmodels.M_User.objects.get(id=user_id) exceptException: returnNone
当然经过这些修改后最终的安全性比起django自带的降低很多,但是需求就是这样的,必须满足。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。