secrets --- 機密を扱うために安全な乱数を生成する

Added in version 3.6.

ソースコード: Lib/secrets.py


secrets モジュールを使って、パスワードやアカウント認証、セキュリティトークンなどの機密を扱うのに適した、暗号学的に強い乱数を生成することができます。

特に、 random モジュールのデフォルトの擬似乱数ジェネレータよりも secrets を使用するべきです。 random モジュールはモデル化やシミュレーション向けで、セキュリティや暗号学的に設計されてはいません。

参考

PEP 506

乱数

secrets モジュールは OS が提供する最も安全な乱雑性のソースへのアクセスを提供します。

class secrets.SystemRandom

OS が提供する最も高品質なソースを用いて乱数を生成するためのクラスです。更に詳しいことについては 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)

Return a random byte string containing nbytes number of bytes.

If nbytes is not specified or None, DEFAULT_ENTROPY is used instead.

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

Return a random text string, in hexadecimal. The string has nbytes random bytes, each byte converted to two hex digits.

If nbytes is not specified or None, DEFAULT_ENTROPY is used instead.

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

Return a random URL-safe text string, containing nbytes random bytes. The text is Base64 encoded, so on average each byte results in approximately 1.3 characters.

If nbytes is not specified or None, DEFAULT_ENTROPY is used instead.

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

トークンは何バイト使うべきか?

総当たり攻撃 に耐えるには、トークンは十分にランダムでなければなりません。残念なことに、コンピュータの性能が向上し、より短時間により多くの推測ができるようになるにつれ、十分とされるランダムさというのは必然的に増えます。2015 年の時点で、secrets モジュールに想定される通常の用途では、32 バイト (256 ビット) のランダムさは十分と考えられています。

独自の長さのトークンを扱いたい場合、様々な token_* 関数に int 引数で渡すことで、トークンに使用するランダムさを明示的に指定することができます。引数はランダムさのバイト数として使用されます。

Otherwise, if no argument is provided, or if the argument is None, the token_* functions use DEFAULT_ENTROPY instead.

secrets.DEFAULT_ENTROPY

Default number of bytes of randomness used by the token_* functions.

The exact value is subject to change at any time, including during maintenance releases.

その他の関数

secrets.compare_digest(a, b)

文字列または bytes-like オブジェクト ab が等しければ True を、そうでなければ False を返します。比較は タイミング攻撃 のリスクを減らす "定数時間比較" の方法で行われます。詳細については hmac.compare_digest() を参照してください。

レシピとベストプラクティス

この節では secrets を使用してセキュリティの基礎的なレベルを扱う際のレシピとベストプラクティスを説明します。

8文字のアルファベットと数字を含むパスワードを生成するには:

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

注釈

アプリケーションは、平文であろうと暗号化されていようと、 復元可能な形式でパスワードを保存 してはいけません。パスワードは暗号学的に強い一方向 (非可逆) ハッシュ関数を用いてソルトしハッシュしなければなりません。

アルファべットと数字からなり、小文字を少なくとも1つと数字を少なくとも3つ含む、10文字のパスワードを生成するには:

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()