您好,登錄后才能下訂單哦!
一、源碼分析
Django 發(fā)布的 1.4 版本中包含了一些安全方面的重要提升。其中一個(gè)是使用 PBKDF2 密碼加密算法代替了 SHA1 。另外一個(gè)特性是你可以添加自己的密碼加密方法。
Django 會(huì)使用你提供的第一個(gè)密碼加密方法(在你的 setting.py 文件里要至少有一個(gè)方法)
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, password, 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, password, salt, iterations=None): assert password is not None assert salt and '$' not in salt if not iterations: 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) def verify(self, password, encoded): algorithm, iterations, salt, hash = encoded.split('$', 3) assert algorithm == self.algorithm encoded_2 = self.encode(password, salt, int(iterations)) return constant_time_compare(encoded, encoded_2) def safe_summary(self, encoded): algorithm, iterations, salt, hash = encoded.split('$', 3) assert algorithm == self.algorithm return OrderedDict([ (_('algorithm'), algorithm), (_('iterations'), iterations), (_('salt'), mask_hash(salt)), (_('hash'), mask_hash(hash)), ]) def must_update(self, encoded): algorithm, iterations, salt, hash = encoded.split('$', 3) return int(iterations) != self.iterations def harden_runtime(self, password, encoded): algorithm, iterations, salt, hash = encoded.split('$', 3) extra_iterations = self.iterations - int(iterations) if extra_iterations > 0: self.encode(password, salt, extra_iterations)
正如你看到那樣,你必須繼承自BasePasswordHasher,并且重寫 verify() , encode() 以及 safe_summary() 方法。
Django 是使用 PBKDF 2算法與36,000次的迭代使得它不那么容易被暴力破解法輕易攻破。密碼用下面的格式儲(chǔ)存:
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', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ]
2、再來看MyMD5PasswordHasher,這個(gè)是我自定義的加密方式,就是基本的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, password, salt): assert password is not None hash = hashlib.md5(password).hexdigest().upper() return hash def verify(self, password, encoded): encoded_2 = self.encode(password, '') return encoded.upper() == encoded_2.upper() def safe_summary(self, encoded): return OrderedDict([ (_('algorithm'), algorithm), (_('salt'), ''), (_('hash'), mask_hash(hash)), ])
之后可以在數(shù)據(jù)庫中看到,密碼確實(shí)使用了自定義的加密方式。
3、修改認(rèn)證方式
AUTHENTICATION_BACKENDS = ( 'framework.mybackend.MyBackend', #新加 'django.contrib.auth.backends.ModelBackend', 'guardian.backends.ObjectPermissionBackend', )
4、再來看自定義的認(rèn)證方式
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
當(dāng)然經(jīng)過這些修改后最終的安全性比起django自帶的降低很多,但是需求就是這樣的,必須滿足。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。