密碼管理在非必要情況下一般不會重新發(fā)明,Django致力于提供一套安全、靈活的工具集來管理用戶密碼。本文檔描述Django存儲密碼和hash存儲方法配置的方式,以及使用hash密碼的一些實例。
另見
即使用戶可能會使用強密碼,攻擊者也可能竊聽到他們的連接。使用HTTPS來避免在HTTP連接上發(fā)送密碼(或者任何敏感的數(shù)據(jù)),因為否則密碼又被嗅探的風險。
Django通常使用PBKDF2來提供靈活的密碼儲存系統(tǒng)。
User 對象的password屬性是一個這種格式的字符串:
<algorithm>$<iterations>$<salt>$<hash>
那些就是用于儲存用戶密碼的部分,以美元字符分分隔。它們由哈希算法、算法迭代次數(shù)(工作因數(shù))、隨機的salt、以及生成的密碼哈希值組成。算法是Django可以使用的,單向哈希或者密碼儲存算法之一,請見下文。迭代描述了算法在哈希上執(zhí)行的次數(shù)。salt是隨機的種子值,哈希值是這個單向函數(shù)的結果。
通常,Django以SHA256的哈希值使用PBKDF2算法,由NIST推薦的一種密碼伸縮機制。這對于大多數(shù)用戶都很有效:它非常安全,需要大量的計算來破解。
然而,取決于你的需求,你可以選擇一個不同的算法,或者甚至使用自定義的算法來滿足你的特定的安全環(huán)境。不過,大多數(shù)用戶并不需要這樣做 -- 如果你不確定,最好不要這樣。如果你打算這樣做,請繼續(xù)閱讀:
DJango通過訪問PASSWORD_HASHERS設置來選擇要使用的算法。這里有一個列表,列出了Django支持的哈希算法類。列表的第一個元素 (即settings.PASSWORD_HASHERS[0]) 會用于儲存密碼, 所有其它元素都是用于驗證的哈希值,它們可以用于檢查現(xiàn)有的密碼。意思是如果你打算使用不同的算法,你需要修改PASSWORD_HASHERS,來將你最喜歡的算法在列表中放在首位。
PASSWORD_HASHERS默認為:
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher',
)
這意味著,Django會使用 PBKDF2 儲存所有密碼,但是支持使用 PBKDF2SHA1, bcrypt, SHA1等等算法來檢查儲存的密碼。下一節(jié)會描述一些通用的方法,高級用戶可能想通過它來修改這個設置。
Bcrypt是一種流行的密碼儲存算法,它特意被設計用于長期的密碼儲存。Django并沒有默認使用它,由于它需要使用三方的庫,但是由于很多人都想使用它,Django會以最小的努力來支持。
執(zhí)行以下步驟來作為你的默認儲存算法來使用Bcrypt:
安裝bcrypt 庫。這可以通過運行pip install django[bcrypt],,或者下載并運行 python setup.py install來實現(xiàn)。
修改 PASSWORD_HASHERS ,將 BCryptSHA256PasswordHasher放在首位。也就是說,在你的設置文件中應該:
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher',
)
(你應該將其它元素留在列表中,否則Django不能升級密碼;見下文)。
配置完畢 -- 現(xiàn)在Django會使用Bcrypt作為默認的儲存算法。
BCryptPasswordHasher的密碼截斷
bcrypt的設計者會在72個字符處截斷所有的密碼,這意味著bcrypt(password_with_100_chars) == bcrypt(password_with_100_chars[:72])。原生的 BCryptPasswordHasher 并不會做任何的特殊處理, 所以它也會受到這一隱藏密碼長度限制的約束。BCryptSHA256PasswordHasher 通過事先使用 sha256生成哈希來解決這一問題。這樣就可以防止密碼截斷了,所以你還是應該優(yōu)先考慮BCryptPasswordHasher。這個截斷帶來的實際效果很微不足道,因為大多數(shù)用戶不會使用長度超過72的密碼,并且即使在72個字符處截斷,破解brypt所需的計算能力依然是天文數(shù)字。雖然如此,我們還是推薦使用BCryptSHA256PasswordHasher ,根據(jù) “有備無患”的原則。
其它 bcrypt 的實現(xiàn)
有一些其它的bcrypt 實現(xiàn),可以讓你在Django中使用它。Django的bcrypt 支持并不直接兼容這些實現(xiàn)。你需要修改數(shù)據(jù)庫中的哈希值,改為 bcrypt$(raw bcrypt output)的形式,來升級它們。例如: bcrypt$$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy。
PBKDF2 和bcrypt 算法使用大量的哈希迭代或循環(huán)。這會有意拖慢攻擊者,使對哈希密碼的攻擊更難以進行。然而,隨著計算機能力的不斷增加,迭代的次數(shù)也需要增加。我們選了一個合理的默認值(并且在Django的每個發(fā)行版會不斷增加),但是你可能想要調高或者調低它,取決于你的安全需求和計算能力。要想這樣做,你可以繼承相應的算法,并且覆寫iterations參數(shù)。例如,增加PBKDF2算法默認使用的迭代次數(shù):
創(chuàng)建django.contrib.auth.hashers.PBKDF2PasswordHasher的子類:
from django.contrib.auth.hashers import PBKDF2PasswordHasher
class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher):
"""
A subclass of PBKDF2PasswordHasher that uses 100 times more iterations.
"""
iterations = PBKDF2PasswordHasher.iterations * 100
把它保存在項目中的某個位置。例如,把它放在類似于myproject/hashers.py的文件中。
將你的新的hasher作為第一個元素添加到PASSWORD_HASHERS:
PASSWORD_HASHERS = (
'myproject.hashers.MyPBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher',
)
配置完畢 -- 現(xiàn)在DJango在儲存使用PBKDF2的密碼時會使用更多的迭代次數(shù)。
用戶登錄之后,如果他們的密碼沒有以首選的密碼算法來儲存,Django會自動將算法升級為首選的那個。這意味著Django中舊的安裝會在用戶登錄時自動變得更加安全,并且你可以隨意在新的(或者更好的)儲存算法發(fā)明之后切換到它們。
然而,Django只會升級在 PASSWORD_HASHERS中出現(xiàn)的算法,所以升級到新系統(tǒng)時,你應該確保不要 _移除_列表中的元素。如果你移除了,使用列表中沒有的算法的用戶不會被升級。修改PBKDF2迭代次數(shù)之后,密碼也會被升級。
django.contrib.auth.hashers模塊提供了一系列的函數(shù)來創(chuàng)建和驗證哈希密碼。你可以獨立于User模型之外使用它們。
check_password(password, encoded)[source]
如果你打算通過比較純文本密碼和數(shù)據(jù)庫中哈希后的密碼來手動驗證用戶,要使用check_password()這一便捷的函數(shù)。它接收兩個參數(shù):要檢查的純文本密碼,和數(shù)據(jù)庫中用戶的password字段的完整值。如果二者匹配,返回True ,否則返回False 。
make_password(password, salt=None, hasher='default')[source]
以當前應用所使用的格式創(chuàng)建哈希密碼。它接受一個必需參數(shù):純文本密碼。如果你不想使用默認值(PASSWORD_HASHERS設置的首選項),你可以提供salt值和要使用的哈希算法,它們是可選的。當前支持的算法是: 'pbkdf2_sha256', 'pbkdf2_sha1', 'bcrypt_sha256' (參見在 Django中使用Bcrypt), 'bcrypt', 'sha1', 'md5', 'unsalted_md5' (僅僅用于向后兼容) 和 'crypt' (如果你安裝了 crypt庫)。如果password參數(shù)是None,會返回一個不可用的密碼(它永遠不會被check_password()接受)。
is_password_usable(_encodedpassword)[source]
檢查提供的字符串是否是可以用check_password()驗證的哈希密碼。
譯者:Django 文檔協(xié)作翻譯小組,原文:Password management。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉載請保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606。