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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。