一、源码分析
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加密方式。
class BasePasswordHasher(object): """ Abstract base class for password hashers When creating your own hasher,you need to override algorithm,verify(),encode() and safe_summary(). PasswordHasher objects are immutable. """ algorithm = None library = None def _load_library(self): if self.library is not None: if isinstance(self.library,(tuple,list)): name,mod_path = self.library else: name = mod_path = self.library try: module = importlib.import_module(mod_path) except ImportError: raise ValueError("Couldn't load %s password algorithm " "library" % name) return module raise ValueError("Hasher '%s' doesn't specify a library attribute" % self.__class__) def salt(self): """ Generates a cryptographically secure nonce salt in ascii """ return get_random_string() def verify(self,password,encoded): """ Checks if the given password is correct """ raise NotImplementedError() def encode(self,salt): """ Creates an encoded database value The result is normally formatted as "algorithm$salt$hash" and must be fewer than 128 characters. """ raise NotImplementedError() def safe_summary(self,encoded): """ Returns a summary of safe values The result is a dictionary and will be used where the password field must be displayed to construct a safe representation of the password. """ raise NotImplementedError() class PBKDF2PasswordHasher(BasePasswordHasher): """ Secure password hashing using the PBKDF2 algorithm (recommended) Configured to use PBKDF2 + HMAC + SHA256. The result is a 64 byte binary string. Iterations may be changed safely but you must rename the algorithm if you change SHA256. """ algorithm = "pbkdf2_sha256" iterations = 36000 digest = hashlib.sha256 def encode(self,salt,iterations=None): assert password is not None assert salt and '$' not in salt if not iterations: iterations = self.iterations hash = pbkdf2(password,iterations,digest=self.digest) hash = base64.b64encode(hash).decode('ascii').strip() return "%s$%d$%s$%s" % (self.algorithm,hash) def verify(self,encoded): algorithm,hash = encoded.split('$',3) assert algorithm == self.algorithm encoded_2 = self.encode(password,int(iterations)) return constant_time_compare(encoded,encoded_2) def safe_summary(self,3) assert algorithm == self.algorithm return OrderedDict([ (_('algorithm'),algorithm),(_('iterations'),iterations),(_('salt'),mask_hash(salt)),(_('hash'),mask_hash(hash)),]) def must_update(self,3) return int(iterations) != self.iterations def harden_runtime(self,3) extra_iterations = self.iterations - int(iterations) if extra_iterations > 0: self.encode(password,extra_iterations)
正如你看到那样,你必须继承自BasePasswordHasher,并且重写 verify() , encode() 以及 safe_summary() 方法。
Django 是使用 PBKDF 2算法与36,000次的迭代使得它不那么容易被暴力破解法轻易攻破。密码用下面的格式储存:
algorithm$number of iterations$salt$password hash”
例:pbkdf2_sha256$36000$Lx7auRCc8FUI$eG9lX66cKFTos9sEcihhiSCjI6uqbr9ZrO+Iq3H9xDU=
1、在settings.py中加入自定义的加密算法:
PASSWORD_HASHERS = [ 'myproject.hashers.MyMD5PasswordHasher','django.contrib.auth.hashers.PBKDF2PasswordHasher',]
2、再来看MyMD5PasswordHasher,这个是我自定义的加密方式,就是基本的md5,而django的MD5PasswordHasher是加盐的:
from django.contrib.auth.hashers import BasePasswordHasher,MD5PasswordHasher from django.contrib.auth.hashers import mask_hash import hashlib class MyMD5PasswordHasher(MD5PasswordHasher): algorithm = "mymd5" def encode(self,salt): assert password is not None hash = hashlib.md5(password).hexdigest().upper() return hash def verify(self,encoded): encoded_2 = self.encode(password,'') return encoded.upper() == encoded_2.upper() def safe_summary(self,encoded): return OrderedDict([ (_('algorithm'),''),])
3、修改认证方式
AUTHENTICATION_BACKENDS = ( 'framework.mybackend.MyBackend',#新加 'django.contrib.auth.backends.ModelBackend','guardian.backends.ObjectPermissionBackend',)
4、再来看自定义的认证方式
framework.mybackend.py: import hashlib from pro import models from django.contrib.auth.backends import ModelBackend class MyBackend(ModelBackend): def authenticate(self,username=None,password=None): try: user = models.M_User.objects.get(username=username) print user except Exception: print 'no user' return None if hashlib.md5(password).hexdigest().upper() == user.password: return user return None def get_user(self,user_id): try: return models.M_User.objects.get(id=user_id) except Exception: return None原文链接:https://www.f2er.com/python/535064.html