Django密碼存儲(chǔ)策略分析
一、源碼分析
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í)有所幫助,也希望大家多多支持腳本之家。
- Django中密碼的加密、驗(yàn)密、解密操作
- Django通用類視圖實(shí)現(xiàn)忘記密碼重置密碼功能示例
- Django實(shí)現(xiàn)發(fā)送郵件找回密碼功能
- Django密碼系統(tǒng)實(shí)現(xiàn)過程詳解
- django中賬號(hào)密碼驗(yàn)證登陸功能的實(shí)現(xiàn)方法
- Django管理員賬號(hào)和密碼忘記的完美解決方法
- Django 忘記管理員或忘記管理員密碼 重設(shè)登錄密碼的方法
- Pycharm 創(chuàng)建 Django admin 用戶名和密碼的實(shí)例
- django 開發(fā)忘記密碼通過郵箱找回功能示例
- 利用Django內(nèi)置的認(rèn)證視圖實(shí)現(xiàn)用戶密碼重置功能詳解
相關(guān)文章
python 實(shí)現(xiàn)docx與doc文件的互相轉(zhuǎn)換
這篇文章主要介紹了python 實(shí)現(xiàn)docx與doc文件的互相轉(zhuǎn)換操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-03-03
python數(shù)據(jù)分析之DataFrame內(nèi)存優(yōu)化
pandas處理幾百兆的dataframe是沒有問題的,但是我們?cè)谔幚韼讉€(gè)G甚至更大的數(shù)據(jù)時(shí),就會(huì)特別占用內(nèi)存,對(duì)內(nèi)存小的用戶特別不好,所以對(duì)數(shù)據(jù)進(jìn)行壓縮是很有必要的,本文就介紹了python DataFrame內(nèi)存優(yōu)化,感興趣的可以了解一下2021-07-07
解決Python中報(bào)錯(cuò)TypeError: must be str, not bytes問題
這篇文章主要介紹了解決Python中報(bào)錯(cuò)TypeError: must be str, not bytes問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-04-04
PyQt中使用QProcess運(yùn)行一個(gè)進(jìn)程的示例代碼
這篇文章主要介紹了在PyQt中使用QProcess運(yùn)行一個(gè)進(jìn)程,本例中通過按下按鈕,啟動(dòng)了windows系統(tǒng)自帶的記事本程序,即notepad.exe, 因?yàn)樗趙indows的系統(tǒng)目錄下,該目錄已經(jīng)加在了系統(tǒng)的PATH環(huán)境變量中,所以不需要特別指定路徑,需要的朋友可以參考下2022-12-12
python日記(使用TCP實(shí)現(xiàn)的對(duì)話客戶端和服務(wù)器)
這篇文章主要為大家介紹了python使用TCP實(shí)現(xiàn)的對(duì)話客戶端和服務(wù)器實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03

