1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
:mod:`secrets` --- Generate secure random numbers for managing secrets
======================================================================
.. module:: secrets
:synopsis: Generate secure random numbers for managing secrets.
.. moduleauthor:: Steven D'Aprano <steve+python@pearwood.info>
.. sectionauthor:: Steven D'Aprano <steve+python@pearwood.info>
.. versionadded:: 3.6
.. testsetup::
from secrets import *
__name__ = '<doctest>'
**Source code:** :source:`Lib/secrets.py`
-------------
The :mod:`secrets` module is used for generating cryptographically strong
random numbers suitable for managing data such as passwords, account
authentication, security tokens, and related secrets.
In particular, :mod:`secrets` should be used in preference to the
default pseudo-random number generator in the :mod:`random` module, which
is designed for modelling and simulation, not security or cryptography.
.. seealso::
:pep:`506`
Random numbers
--------------
The :mod:`secrets` module provides access to the most secure source of
randomness that your operating system provides.
.. class:: SystemRandom
A class for generating random numbers using the highest-quality
sources provided by the operating system. See
:class:`random.SystemRandom` for additional details.
.. function:: choice(sequence)
Return a randomly-chosen element from a non-empty sequence.
.. function:: randbelow(n)
Return a random int in the range [0, *n*).
.. function:: randbits(k)
Return an int with *k* random bits.
Generating tokens
-----------------
The :mod:`secrets` module provides functions for generating secure
tokens, suitable for applications such as password resets,
hard-to-guess URLs, and similar.
.. function:: token_bytes([nbytes=None])
Return a random byte string containing *nbytes* number of bytes.
If *nbytes* is ``None`` or not supplied, a reasonable default is
used.
.. doctest::
>>> token_bytes(16) #doctest:+SKIP
b'\xebr\x17D*t\xae\xd4\xe3S\xb6\xe2\xebP1\x8b'
.. function:: 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
``None`` or not supplied, a reasonable default is used.
.. doctest::
>>> token_hex(16) #doctest:+SKIP
'f9bf78b9a18ce6d46a0cd2b0b86df9da'
.. function:: 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 ``None`` or not
supplied, a reasonable default is used.
.. doctest::
>>> token_urlsafe(16) #doctest:+SKIP
'Drmhze6EPcv0fN_81Bj-nA'
How many bytes should tokens use?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To be secure against
`brute-force attacks <https://en.wikipedia.org/wiki/Brute-force_attack>`_,
tokens need to have sufficient randomness. Unfortunately, what is
considered sufficient will necessarily increase as computers get more
powerful and able to make more guesses in a shorter period. As of 2015,
it is believed that 32 bytes (256 bits) of randomness is sufficient for
the typical use-case expected for the :mod:`secrets` module.
For those who want to manage their own token length, you can explicitly
specify how much randomness is used for tokens by giving an :class:`int`
argument to the various ``token_*`` functions. That argument is taken
as the number of bytes of randomness to use.
Otherwise, if no argument is provided, or if the argument is ``None``,
the ``token_*`` functions will use a reasonable default instead.
.. note::
That default is subject to change at any time, including during
maintenance releases.
Other functions
---------------
.. function:: compare_digest(a, b)
Return ``True`` if strings *a* and *b* are equal, otherwise ``False``,
in such a way as to reduce the risk of
`timing attacks <https://codahale.com/a-lesson-in-timing-attacks/>`_.
See :func:`hmac.compare_digest` for additional details.
Recipes and best practices
--------------------------
This section shows recipes and best practices for using :mod:`secrets`
to manage a basic level of security.
Generate an eight-character alphanumeric password:
.. testcode::
import string
import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))
.. note::
Applications should not
`store passwords in a recoverable format <http://cwe.mitre.org/data/definitions/257.html>`_,
whether plain text or encrypted. They should be salted and hashed
using a cryptographically-strong one-way (irreversible) hash function.
Generate a ten-character alphanumeric password with at least one
lowercase character, at least one uppercase character, and at least
three digits:
.. testcode::
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
Generate an `XKCD-style passphrase <https://xkcd.com/936/>`_:
.. testcode::
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))
Generate a hard-to-guess temporary URL containing a security token
suitable for password recovery applications:
.. testcode::
import secrets
url = 'https://mydomain.com/reset=' + secrets.token_urlsafe()
..
# This modeline must appear within the last ten lines of the file.
kate: indent-width 3; remove-trailing-space on; replace-tabs on; encoding utf-8;
|