鍍金池/ 教程/ Python/ Django中的密碼管理
點(diǎn)擊劫持保護(hù)
安全問(wèn)題歸檔
Model 類(lèi)參考
將遺留數(shù)據(jù)庫(kù)整合到Django
關(guān)聯(lián)對(duì)象參考
內(nèi)建基于類(lèi)的視圖的API
聚合
Django 中的用戶(hù)認(rèn)證
django.contrib.humanize
Django管理文檔生成器
分頁(yè)
使用Django輸出CSV
加密簽名
文件儲(chǔ)存API
安全
Django中的測(cè)試
國(guó)際化和本地化
為Django編寫(xiě)首個(gè)補(bǔ)丁
條件表達(dá)式
日志
模型元選項(xiàng)
部署靜態(tài)文件
執(zhí)行查詢(xún)
使用Django認(rèn)證系統(tǒng)
基于類(lèi)的視圖
中間件
編寫(xiě)自定義的django-admin命令
Django 的設(shè)置
格式本地化
數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)優(yōu)化
錯(cuò)誤報(bào)告
基于類(lèi)的內(nèi)建通用視圖
編寫(xiě)自定義存儲(chǔ)系統(tǒng)
編寫(xiě)你的第一個(gè) Django 程序 第3部分
編寫(xiě)數(shù)據(jù)庫(kù)遷移
使用表單
編寫(xiě)你的第一個(gè) Django 程序 第2部分
編寫(xiě)你的第一個(gè) Django 程序 第1部分
如何使用會(huì)話(huà)
系統(tǒng)檢查框架
新手入門(mén)
信號(hào)
編寫(xiě)視圖
如何使用WSGI 部署
編寫(xiě)你的第一個(gè)Django應(yīng)用,第6部分
常見(jiàn)的網(wǎng)站應(yīng)用工具
Widgets
內(nèi)建的視圖
模型實(shí)例參考
視圖層
Django中的密碼管理
高級(jí)教程:如何編寫(xiě)可重用的應(yīng)用
國(guó)際化和本地化
"本地特色"附加功能
TemplateResponse 和 SimpleTemplateResponse
模式編輯器
文件上傳
快速安裝指南
部署 Django
表單 API
表單素材 ( <code>Media</code> 類(lèi))
管理文件
其它核心功能
查找 API 參考
表單
Admin
數(shù)據(jù)庫(kù)函數(shù)
自定義查找
使用基于類(lèi)的視圖處理表單
管理操作
開(kāi)發(fā)過(guò)程
編寫(xiě)你的第一個(gè)Django應(yīng)用,第5部分
進(jìn)行原始的sql查詢(xún)
模型層
多數(shù)據(jù)庫(kù)
編寫(xiě)你的第一個(gè) Django 程序 第4部分
Django安全
Django 初探
Django異常
重定向應(yīng)用
按需內(nèi)容處理
管理器
視圖裝飾器
驗(yàn)證器
使用Django輸出PDF
File對(duì)象
Django 的快捷函數(shù)
基于類(lèi)的通用視圖 —— 索引
為模型提供初始數(shù)據(jù)
模板層
URL調(diào)度器
中間件
模型

Django中的密碼管理

密碼管理在非必要情況下一般不會(huì)重新發(fā)明,Django致力于提供一套安全、靈活的工具集來(lái)管理用戶(hù)密碼。本文檔描述Django存儲(chǔ)密碼和hash存儲(chǔ)方法配置的方式,以及使用hash密碼的一些實(shí)例。

另見(jiàn)

即使用戶(hù)可能會(huì)使用強(qiáng)密碼,攻擊者也可能竊聽(tīng)到他們的連接。使用HTTPS來(lái)避免在HTTP連接上發(fā)送密碼(或者任何敏感的數(shù)據(jù)),因?yàn)榉駝t密碼又被嗅探的風(fēng)險(xiǎn)。

Django如何儲(chǔ)存密碼

Django通常使用PBKDF2來(lái)提供靈活的密碼儲(chǔ)存系統(tǒng)。

User 對(duì)象的password屬性是一個(gè)這種格式的字符串:

<algorithm>$<iterations>$<salt>$<hash>

那些就是用于儲(chǔ)存用戶(hù)密碼的部分,以美元字符分分隔。它們由哈希算法、算法迭代次數(shù)(工作因數(shù))、隨機(jī)的salt、以及生成的密碼哈希值組成。算法是Django可以使用的,單向哈?;蛘呙艽a儲(chǔ)存算法之一,請(qǐng)見(jiàn)下文。迭代描述了算法在哈希上執(zhí)行的次數(shù)。salt是隨機(jī)的種子值,哈希值是這個(gè)單向函數(shù)的結(jié)果。

通常,Django以SHA256的哈希值使用PBKDF2算法,由NIST推薦的一種密碼伸縮機(jī)制。這對(duì)于大多數(shù)用戶(hù)都很有效:它非常安全,需要大量的計(jì)算來(lái)破解。

然而,取決于你的需求,你可以選擇一個(gè)不同的算法,或者甚至使用自定義的算法來(lái)滿(mǎn)足你的特定的安全環(huán)境。不過(guò),大多數(shù)用戶(hù)并不需要這樣做 -- 如果你不確定,最好不要這樣。如果你打算這樣做,請(qǐng)繼續(xù)閱讀:

DJango通過(guò)訪(fǎng)問(wèn)PASSWORD_HASHERS設(shè)置來(lái)選擇要使用的算法。這里有一個(gè)列表,列出了Django支持的哈希算法類(lèi)。列表的第一個(gè)元素 (即settings.PASSWORD_HASHERS[0]) 會(huì)用于儲(chǔ)存密碼, 所有其它元素都是用于驗(yàn)證的哈希值,它們可以用于檢查現(xiàn)有的密碼。意思是如果你打算使用不同的算法,你需要修改PASSWORD_HASHERS,來(lái)將你最喜歡的算法在列表中放在首位。

PASSWORD_HASHERS默認(rèn)為:

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會(huì)使用 PBKDF2 儲(chǔ)存所有密碼,但是支持使用 PBKDF2SHA1, bcrypt, SHA1等等算法來(lái)檢查儲(chǔ)存的密碼。下一節(jié)會(huì)描述一些通用的方法,高級(jí)用戶(hù)可能想通過(guò)它來(lái)修改這個(gè)設(shè)置。

在Django中使用bcrypt

Bcrypt是一種流行的密碼儲(chǔ)存算法,它特意被設(shè)計(jì)用于長(zhǎng)期的密碼儲(chǔ)存。Django并沒(méi)有默認(rèn)使用它,由于它需要使用三方的庫(kù),但是由于很多人都想使用它,Django會(huì)以最小的努力來(lái)支持。

執(zhí)行以下步驟來(lái)作為你的默認(rèn)儲(chǔ)存算法來(lái)使用Bcrypt:

  1. 安裝bcrypt 庫(kù)。這可以通過(guò)運(yùn)行pip install django[bcrypt],,或者下載并運(yùn)行 python setup.py install來(lái)實(shí)現(xiàn)。

  2. 修改 PASSWORD_HASHERS ,將 BCryptSHA256PasswordHasher放在首位。也就是說(shuō),在你的設(shè)置文件中應(yīng)該:

      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',
      )
    

    (你應(yīng)該將其它元素留在列表中,否則Django不能升級(jí)密碼;見(jiàn)下文)。

配置完畢 -- 現(xiàn)在Django會(huì)使用Bcrypt作為默認(rèn)的儲(chǔ)存算法。

BCryptPasswordHasher的密碼截?cái)?/p>

bcrypt的設(shè)計(jì)者會(huì)在72個(gè)字符處截?cái)嗨械拿艽a,這意味著bcrypt(password_with_100_chars) == bcrypt(password_with_100_chars[:72])。原生的 BCryptPasswordHasher 并不會(huì)做任何的特殊處理, 所以它也會(huì)受到這一隱藏密碼長(zhǎng)度限制的約束。BCryptSHA256PasswordHasher 通過(guò)事先使用 sha256生成哈希來(lái)解決這一問(wèn)題。這樣就可以防止密碼截?cái)嗔耍阅氵€是應(yīng)該優(yōu)先考慮BCryptPasswordHasher。這個(gè)截?cái)鄮?lái)的實(shí)際效果很微不足道,因?yàn)榇蠖鄶?shù)用戶(hù)不會(huì)使用長(zhǎng)度超過(guò)72的密碼,并且即使在72個(gè)字符處截?cái)?,破解brypt所需的計(jì)算能力依然是天文數(shù)字。雖然如此,我們還是推薦使用BCryptSHA256PasswordHasher ,根據(jù) “有備無(wú)患”的原則。

其它 bcrypt 的實(shí)現(xiàn)

有一些其它的bcrypt 實(shí)現(xiàn),可以讓你在Django中使用它。Django的bcrypt 支持并不直接兼容這些實(shí)現(xiàn)。你需要修改數(shù)據(jù)庫(kù)中的哈希值,改為 bcrypt$(raw bcrypt output)的形式,來(lái)升級(jí)它們。例如: bcrypt$$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy。

增加工作因數(shù)

PBKDF2 和bcrypt 算法使用大量的哈希迭代或循環(huán)。這會(huì)有意拖慢攻擊者,使對(duì)哈希密碼的攻擊更難以進(jìn)行。然而,隨著計(jì)算機(jī)能力的不斷增加,迭代的次數(shù)也需要增加。我們選了一個(gè)合理的默認(rèn)值(并且在Django的每個(gè)發(fā)行版會(huì)不斷增加),但是你可能想要調(diào)高或者調(diào)低它,取決于你的安全需求和計(jì)算能力。要想這樣做,你可以繼承相應(yīng)的算法,并且覆寫(xiě)iterations參數(shù)。例如,增加PBKDF2算法默認(rèn)使用的迭代次數(shù):

  1. 創(chuàng)建django.contrib.auth.hashers.PBKDF2PasswordHasher的子類(lèi):

      from django.contrib.auth.hashers import PBKDF2PasswordHasher
    
      class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher):
          """
          A subclass of PBKDF2PasswordHasher that uses 100 times more iterations.
          """
          iterations = PBKDF2PasswordHasher.iterations * 100
    

    把它保存在項(xiàng)目中的某個(gè)位置。例如,把它放在類(lèi)似于myproject/hashers.py的文件中。

  2. 將你的新的hasher作為第一個(gè)元素添加到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在儲(chǔ)存使用PBKDF2的密碼時(shí)會(huì)使用更多的迭代次數(shù)。

密碼升級(jí)

用戶(hù)登錄之后,如果他們的密碼沒(méi)有以首選的密碼算法來(lái)儲(chǔ)存,Django會(huì)自動(dòng)將算法升級(jí)為首選的那個(gè)。這意味著Django中舊的安裝會(huì)在用戶(hù)登錄時(shí)自動(dòng)變得更加安全,并且你可以隨意在新的(或者更好的)儲(chǔ)存算法發(fā)明之后切換到它們。

然而,Django只會(huì)升級(jí)在 PASSWORD_HASHERS中出現(xiàn)的算法,所以升級(jí)到新系統(tǒng)時(shí),你應(yīng)該確保不要 _移除_列表中的元素。如果你移除了,使用列表中沒(méi)有的算法的用戶(hù)不會(huì)被升級(jí)。修改PBKDF2迭代次數(shù)之后,密碼也會(huì)被升級(jí)。

Manually managing a user’s password

django.contrib.auth.hashers模塊提供了一系列的函數(shù)來(lái)創(chuàng)建和驗(yàn)證哈希密碼。你可以獨(dú)立于User模型之外使用它們。

check_password(password, encoded)[source]

如果你打算通過(guò)比較純文本密碼和數(shù)據(jù)庫(kù)中哈希后的密碼來(lái)手動(dòng)驗(yàn)證用戶(hù),要使用check_password()這一便捷的函數(shù)。它接收兩個(gè)參數(shù):要檢查的純文本密碼,和數(shù)據(jù)庫(kù)中用戶(hù)的password字段的完整值。如果二者匹配,返回True ,否則返回False

make_password(password, salt=None, hasher='default')[source]

以當(dāng)前應(yīng)用所使用的格式創(chuàng)建哈希密碼。它接受一個(gè)必需參數(shù):純文本密碼。如果你不想使用默認(rèn)值(PASSWORD_HASHERS設(shè)置的首選項(xiàng)),你可以提供salt值和要使用的哈希算法,它們是可選的。當(dāng)前支持的算法是: 'pbkdf2_sha256', 'pbkdf2_sha1', 'bcrypt_sha256' (參見(jiàn)在 Django中使用Bcrypt), 'bcrypt', 'sha1', 'md5', 'unsalted_md5' (僅僅用于向后兼容) 和 'crypt' (如果你安裝了 crypt庫(kù))。如果password參數(shù)是None,會(huì)返回一個(gè)不可用的密碼(它永遠(yuǎn)不會(huì)被check_password()接受)。

is_password_usable(_encodedpassword)[source]

檢查提供的字符串是否是可以用check_password()驗(yàn)證的哈希密碼。

譯者:Django 文檔協(xié)作翻譯小組,原文:Password management。

本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請(qǐng)保留作者署名和文章出處。

Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。