# Django中的密碼管理
密碼管理在非必要情況下一般不會重新發明,Django致力于提供一套安全、靈活的工具集來管理用戶密碼。本文檔描述Django存儲密碼和hash存儲方法配置的方式,以及使用hash密碼的一些實例。
另見
即使用戶可能會使用強密碼,攻擊者也可能竊聽到他們的連接。使用[_HTTPS_](../security.html#security-recommendation-ssl)來避免在HTTP連接上發送密碼(或者任何敏感的數據),因為否則密碼又被嗅探的風險。
## Django如何儲存密碼
Django通常使用PBKDF2來提供靈活的密碼儲存系統。
[`User`](../../ref/contrib/auth.html#django.contrib.auth.models.User "django.contrib.auth.models.User") 對象的[`password`](../../ref/contrib/auth.html#django.contrib.auth.models.User.password "django.contrib.auth.models.User.password")屬性是一個這種格式的字符串:
```
<algorithm>$<iterations>$<salt>$<hash>
```
那些就是用于儲存用戶密碼的部分,以美元字符分分隔。它們由哈希算法、算法迭代次數(工作因數)、隨機的salt、以及生成的密碼哈希值組成。算法是Django可以使用的,單向哈希或者密碼儲存算法之一,請見下文。迭代描述了算法在哈希上執行的次數。salt是隨機的種子值,哈希值是這個單向函數的結果。
通常,Django以SHA256的哈希值使用[PBKDF2](http://en.wikipedia.org/wiki/PBKDF2)算法,由[NIST](http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf)推薦的一種密碼伸縮機制。這對于大多數用戶都很有效:它非常安全,需要大量的計算來破解。
然而,取決于你的需求,你可以選擇一個不同的算法,或者甚至使用自定義的算法來滿足你的特定的安全環境。不過,大多數用戶并不需要這樣做 -- 如果你不確定,最好不要這樣。如果你打算這樣做,請繼續閱讀:
DJango通過訪問[`PASSWORD_HASHERS`](../../ref/settings.html#std:setting-PASSWORD_HASHERS)設置來選擇要使用的算法。這里有一個列表,列出了Django支持的哈希算法類。列表的第一個元素 (即`settings.`PASSWORD_HASHERS[0]) 會用于儲存密碼, 所有其它元素都是用于驗證的哈希值,它們可以用于檢查現有的密碼。意思是如果你打算使用不同的算法,你需要修改[`PASSWORD_HASHERS`](../../ref/settings.html#std:setting-PASSWORD_HASHERS),來將你最喜歡的算法在列表中放在首位。
[`PASSWORD_HASHERS`](../../ref/settings.html#std:setting-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](http://en.wikipedia.org/wiki/PBKDF2) 儲存所有密碼,但是支持使用 PBKDF2SHA1, [bcrypt](http://en.wikipedia.org/wiki/Bcrypt), [SHA1](http://en.wikipedia.org/wiki/SHA1)等等算法來檢查儲存的密碼。下一節會描述一些通用的方法,高級用戶可能想通過它來修改這個設置。
### 在Django中使用bcrypt
[Bcrypt](http://en.wikipedia.org/wiki/Bcrypt)是一種流行的密碼儲存算法,它特意被設計用于長期的密碼儲存。Django并沒有默認使用它,由于它需要使用三方的庫,但是由于很多人都想使用它,Django會以最小的努力來支持。
執行以下步驟來作為你的默認儲存算法來使用Bcrypt:
1. 安裝[bcrypt 庫](https://pypi.python.org/pypi/bcrypt/)。這可以通過運行`pip install django[bcrypt]`,,或者下載并運行 `python setup.py install`來實現。
2. 修改 [`PASSWORD_HASHERS`](../../ref/settings.html#std:setting-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不能升級密碼;見下文)。
配置完畢 -- 現在Django會使用Bcrypt作為默認的儲存算法。
BCryptPasswordHasher的密碼截斷
bcrypt的設計者會在72個字符處截斷所有的密碼,這意味著`bcrypt(password_with_100_chars) == bcrypt(password_with_100_chars[:72])`。原生的 `BCryptPasswordHasher` 并不會做任何的特殊處理, 所以它也會受到這一隱藏密碼長度限制的約束。`BCryptSHA256PasswordHasher` 通過事先使用 sha256生成哈希來解決這一問題。這樣就可以防止密碼截斷了,所以你還是應該優先考慮`BCryptPasswordHasher`。這個截斷帶來的實際效果很微不足道,因為大多數用戶不會使用長度超過72的密碼,并且即使在72個字符處截斷,破解brypt所需的計算能力依然是天文數字。雖然如此,我們還是推薦使用`BCryptSHA256PasswordHasher` ,根據 “有備無患”的原則。
其它 bcrypt 的實現
有一些其它的bcrypt 實現,可以讓你在Django中使用它。Django的bcrypt 支持并不直接兼容這些實現。你需要修改數據庫中的哈希值,改為 `bcrypt$(raw bcrypt output)`的形式,來升級它們。例如: `bcrypt$$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy`。
### 增加工作因數
PBKDF2 和bcrypt 算法使用大量的哈希迭代或循環。這會有意拖慢攻擊者,使對哈希密碼的攻擊更難以進行。然而,隨著計算機能力的不斷增加,迭代的次數也需要增加。我們選了一個合理的默認值(并且在Django的每個發行版會不斷增加),但是你可能想要調高或者調低它,取決于你的安全需求和計算能力。要想這樣做,你可以繼承相應的算法,并且覆寫`iterations`參數。例如,增加PBKDF2算法默認使用的迭代次數:
1. 創建`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`的文件中。
2. 將你的新的hasher作為第一個元素添加到[`PASSWORD_HASHERS`](../../ref/settings.html#std:setting-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',
)
```
配置完畢 -- 現在DJango在儲存使用PBKDF2的密碼時會使用更多的迭代次數。
### 密碼升級
用戶登錄之后,如果他們的密碼沒有以首選的密碼算法來儲存,Django會自動將算法升級為首選的那個。這意味著Django中舊的安裝會在用戶登錄時自動變得更加安全,并且你可以隨意在新的(或者更好的)儲存算法發明之后切換到它們。
然而,Django只會升級在 [`PASSWORD_HASHERS`](../../ref/settings.html#std:setting-PASSWORD_HASHERS)中出現的算法,所以升級到新系統時,你應該確保不要 _移除_列表中的元素。如果你移除了,使用列表中沒有的算法的用戶不會被升級。修改PBKDF2迭代次數之后,密碼也會被升級。
## Manually managing a user’s password
[`django.contrib.auth.hashers`](#module-django.contrib.auth.hashers "django.contrib.auth.hashers")模塊提供了一系列的函數來創建和驗證哈希密碼。你可以獨立于`User`模型之外使用它們。
`check_password`(_password_, _encoded_)[[source]](../../_modules/django/contrib/auth/hashers.html#check_password)
如果你打算通過比較純文本密碼和數據庫中哈希后的密碼來手動驗證用戶,要使用[`check_password()`](#django.contrib.auth.hashers.check_password "django.contrib.auth.hashers.check_password")這一便捷的函數。它接收兩個參數:要檢查的純文本密碼,和數據庫中用戶的`password`字段的完整值。如果二者匹配,返回`True` ,否則返回`False` 。
`make_password`(_password_, _salt=None_, _hasher='default'_)[[source]](../../_modules/django/contrib/auth/hashers.html#make_password)
以當前應用所使用的格式創建哈希密碼。它接受一個必需參數:純文本密碼。如果你不想使用默認值(`PASSWORD_HASHERS`設置的首選項),你可以提供salt值和要使用的哈希算法,它們是可選的。當前支持的算法是: `'pbkdf2_sha256'`, `'pbkdf2_sha1'`, `'bcrypt_sha256'` (參見[_在 Django中使用Bcrypt_](#bcrypt-usage)), `'bcrypt'`, `'sha1'`, `'md5'`, `'unsalted_md5'` (僅僅用于向后兼容) 和 `'crypt'` (如果你安裝了 `crypt`庫)。如果password參數是`None`,會返回一個不可用的密碼(它永遠不會被[`check_password()`](#django.contrib.auth.hashers.check_password "django.contrib.auth.hashers.check_password")接受)。
`is_password_usable`(_encoded_password_)[[source]](../../_modules/django/contrib/auth/hashers.html#is_password_usable)
檢查提供的字符串是否是可以用[`check_password()`](#django.contrib.auth.hashers.check_password "django.contrib.auth.hashers.check_password")驗證的哈希密碼。
> 譯者:[Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html),原文:[Password management](https://docs.djangoproject.com/en/1.8/topics/auth/passwords/)。
>
> 本文以 [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/cn/) 協議發布,轉載請保留作者署名和文章出處。
>
> [Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html)人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606。
- 新手入門
- 從零開始
- 概覽
- 安裝
- 教程
- 第1部分:模型
- 第2部分:管理站點
- 第3部分:視圖和模板
- 第4部分:表單和通用視圖
- 第5部分:測試
- 第6部分:靜態文件
- 高級教程
- 如何編寫可重用的應用
- 為Django編寫首個補丁
- 模型層
- 模型
- 模型語法
- 元選項
- 模型類
- 查詢集
- 執行查詢
- 查找表達式
- 模型的實例
- 實例方法
- 訪問關聯對象
- 遷移
- 模式編輯器
- 編寫遷移
- 高級
- 管理器
- 原始的SQL查詢
- 聚合
- 多數據庫
- 自定義查找
- 條件表達式
- 數據庫函數
- 其它
- 遺留的數據庫
- 提供初始數據
- 優化數據庫訪問
- 視圖層
- 基礎
- URL配置
- 視圖函數
- 快捷函數
- 裝飾器
- 參考
- 內建的視圖
- TemplateResponse 對象
- 文件上傳
- 概覽
- File 對象
- 儲存API
- 管理文件
- 自定義存儲
- 基于類的視圖
- 概覽
- 內建顯示視圖
- 內建編輯視圖
- API參考
- 分類索引
- 高級
- 生成 CSV
- 生成 PDF
- 中間件
- 概覽
- 內建的中間件類
- 模板層
- 基礎
- 面向設計師
- 語言概覽
- 人性化
- 面向程序員
- 表單
- 基礎
- 概覽
- 表單API
- 內建的Widget
- 高級
- 整合媒體
- 開發過程
- 設置
- 概覽
- 應用程序
- 異常
- 概覽
- django-admin 和 manage.py
- 添加自定義的命令
- 測試
- 介紹
- 部署
- 概述
- WSGI服務器
- 部署靜態文件
- 通過email追蹤代碼錯誤
- Admin
- 管理操作
- 管理文檔生成器
- 安全
- 安全概述
- 說明Django中的安全問題
- 點擊劫持保護
- 加密簽名
- 國際化和本地化
- 概述
- 本地化WEB UI格式化輸入
- “本地特色”
- 常見的網站應用工具
- 認證
- 概覽
- 使用認證系統
- 密碼管理
- 日志
- 分頁
- 會話
- 數據驗證
- 其它核心功能
- 按需內容處理
- 重定向
- 信號
- 系統檢查框架