Python 3.6 added a new module called secrets that is designed “to provide an obvious way to reliably generate cryptographically strong pseudo-random values suitable for managing secrets, such as account authentication, tokens, and similar”. Python’s random module was never designed for cryptographic use but for modeling and simulation. Of course, you could always use the urandom() function from Python’s os module:
>>> import os >>> os.urandom(8) '\x9c\xc2WCzS\x95\xc8'
But now that we have the secrets module, we can create our own “cryptographically strong pseudo-random values”. Here’s a simple example:
>>> import secrets >>> import string >>> characters = string.ascii_letters + string.digits >>> bad_password = ''.join(secrets.choice(characters) for i in range(8)) >>> bad_password 'SRvM54Z1'
In this example, we import the secrets and the string modules. Next we create a string of uppercase letters and integers. Finally we use the secrets module’s choice() method to choose characters randomly to generate a bad password. The reason I am calling this a bad password is because we aren’t adding symbols to the password. This is actually a fairly decent one compared with what a lot of people use. One of my readers pointed out that another reason this could be considered bad is that the user would probably just write it down on a piece of paper. While that may be true, using dictionary words is typically strongly discouraged so you should learn to use passwords like this or invest in a secure password manager.
Generating Tokens with secrets
The secrets module also provides several methods of generating tokens. Here are some examples:
>>>: secrets.token_bytes() b'\xd1Od\xe0\xe4\xf8Rn\x8cO\xa7XV\x1cb\xd6\x11\xa0\xcaK' >>> secrets.token_bytes(8) b'\xfc,9y\xbe]\x0e\xfb' >>> secrets.token_hex(16) '6cf3baf51c12ebfcbe26d08b6bbe1ac0' >>> secrets.token_urlsafe(16) '5t_jLGlV8yp2Q5tolvBesQ'
The token_bytes function will return a random byte string containing nbytes number of bytes. I didn’t supply a number of bytes in the first example, so Python chose a reasonable number for me. Then I tried calling it again and asking for 8 bytes. The next function we tried is token_hex, which will return a random string in hexadecimal. The last function is token_urlsafe which will return a random URL-safe text string. The text is Base64 encoded too! Note that in practice you should probably use at least 32 bytes for your tokens for them to be secure against a brute-force attack (source).
Wrapping Up
The secrets module is a worthy addition to Python. Frankly I thought something like this should have been added a long time ago. But at least now we have it and now we can safely generate cryptographically strong tokens and passwords. Take some time to check out the documentation for this module as it has a few fun recipes to play around with.
Related Readings
- The secrets module documentation
- What’s new in Python 3.6: secrets module
- PEP 506 — Adding A Secrets Module To The Standard Library
“The reason I am calling this a bad password is because we aren’t using mixed case, numbers and symbols in the password. ”
Isn’t the more important reason this is bad that it is impossible to remember, and will wind up written down on a post-it in the drawer of the person who is trying to use it?
While I agree, I do know people that use passwords like this. I use a password manager for some websites, although that can be annoying too. I updated the article somewhat in response as well.