secrets — 生成安全的隨機數用於管理秘密

在 3.6 版本加入。

原始碼: Lib/secrets.py


secrets 模組用於生成加密強度高的隨機數,適用於管理密碼、賬戶認證、安全令牌和相關秘密等資料。

特別是,secrets 模組應優先於 random 模組中預設的偽隨機數生成器。後者設計用於建模和模擬,而非安全性或密碼學。

參見

PEP 506

隨機數

secrets 模組提供了對作業系統提供的最安全的隨機性來源的訪問。

class secrets.SystemRandom

一個用於使用作業系統提供的最高質量來源生成隨機數的類。有關更多詳細資訊,請參閱 random.SystemRandom

secrets.choice(seq)

從非空序列中返回一個隨機選擇的元素。

secrets.randbelow(exclusive_upper_bound)

返回範圍 [0, exclusive_upper_bound) 內的一個隨機整數。

secrets.randbits(k)

返回一個帶有 k 個隨機位的非負整數。

生成令牌

secrets 模組提供用於生成安全令牌的函式,適用於密碼重置、難以猜測的 URL 等應用程式。

secrets.token_bytes([nbytes=None])

返回一個隨機位元組字串,包含 nbytes 個位元組。如果 nbytesNone 或未提供,則使用一個合理的預設值。

>>> token_bytes(16)
b'\xebr\x17D*t\xae\xd4\xe3S\xb6\xe2\xebP1\x8b'
secrets.token_hex([nbytes=None])

返回一個隨機的十六進位制文字字串。該字串有 nbytes 個隨機位元組,每個位元組轉換為兩位十六進位制數字。如果 nbytesNone 或未提供,則使用一個合理的預設值。

>>> token_hex(16)
'f9bf78b9a18ce6d46a0cd2b0b86df9da'
secrets.token_urlsafe([nbytes=None])

返回一個 URL 安全的隨機文字字串,包含 nbytes 個隨機位元組。文字採用 Base64 編碼,因此平均每個位元組產生約 1.3 個字元。如果 nbytesNone 或未提供,則使用一個合理的預設值。

>>> token_urlsafe(16)
'Drmhze6EPcv0fN_81Bj-nA'

令牌應使用多少位元組?

為了抵禦 暴力攻擊,令牌需要有足夠的隨機性。不幸的是,隨著計算機變得越來越強大,能夠在更短的時間內進行更多的猜測,所謂的“足夠”將必然增加。截至 2015 年,人們認為 32 位元組(256 位)的隨機性對於 secrets 模組所預期的典型用例是足夠的。

對於那些希望自行管理令牌長度的人,可以透過向各種 token_* 函式提供一個 int 引數來明確指定用於令牌的隨機性數量。該引數被視為要使用的隨機性位元組數。

否則,如果未提供引數,或引數為 Nonetoken_* 函式將使用合理的預設值。

備註

該預設值可能隨時更改,包括在維護版本中。

其他函式

secrets.compare_digest(a, b)

如果字串或 類位元組物件 ab 相等,則返回 True,否則返回 False,使用“常數時間比較”來降低 定時攻擊 的風險。有關更多詳細資訊,請參閱 hmac.compare_digest()

秘籍和最佳實踐

本節展示了使用 secrets 管理基本安全級別的秘籍和最佳實踐。

生成一個八個字元的字母數字密碼

import string
import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))

備註

應用程式不應 以可恢復的格式儲存密碼,無論是純文字還是加密的。它們應該使用加密強度高的一次性(不可逆)雜湊函式進行加鹽和雜湊處理。

生成一個十個字元的字母數字密碼,至少包含一個小寫字元、一個大寫字元和三個數字

import string
import secrets
alphabet = string.ascii_letters + string.digits
while True:
    password = ''.join(secrets.choice(alphabet) for i in range(10))
    if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and sum(c.isdigit() for c in password) >= 3):
        break

生成一個 XKCD 風格的密碼短語

import secrets
# On standard Linux systems, use a convenient dictionary file.
# Other platforms may need to provide their own word-list.
with open('/usr/share/dict/words') as f:
    words = [word.strip() for word in f]
    password = ' '.join(secrets.choice(words) for i in range(4))

生成一個難以猜測的臨時 URL,其中包含一個適用於密碼恢復應用程式的安全令牌

import secrets
url = 'https://example.com/reset=' + secrets.token_urlsafe()