Python 3.6 introduced a secrets module for generating a strong and secure random number. In this lesson, you’ll learn how to use secrets.SystemRandom() class and secrets module functions to generate secure random numbers, data, URLs, and secure tokens.

Why use secrets module

The cryptographically secure random generator generates random data using synchronization methods to ensure that no two processes can obtain the same data at the same time.

The random generator provided by the Python random module is a pseudo-random number generator that is not cryptographically secure as a result secrets module is added in Python 3.6 and onwards to secure the random number generator.

Before Python 3.6, we have the os.urandom() and random.SystemRandom class to cryptographically secure random generator.

The secrets module is CSPRNG i.e., cryptographically strong Pseudo-Random Number Generator. It is used to produce random-numbers which are secure and useful in security-sensitive applications. Please refer to PEP – 0506. This PEP is designed to add the secrets module to the Python standard library.

Note – secrets module available only in Python 3.6 and above. If you are using an older version of Python and want to secure a random generator then please refer to How to secure a random generator in Python.

For example, you can use the secrets module for following common security-related functions.

generating random numbers,

Passwords and OTP.

random token.

Password recovery safe URLs, and session keys.

The secrets module is based on os.urandom() and random.SystemRandom(), which are the interface to the operating system’s best source of cryptographic randomness.

On windows, os.urandom() internally uses CryptGenRandom ().

internally uses (). Linux 3.17 and newer, the getrandom() syscall used when available.

syscall used when available. On OpenBSD 5.6 and newer, the C getentropy() function is now used.

Let see how to use the secrets module.

Class secrets.SystemRandom

A class for generating random numbers using the highest-quality sources provided by the operating system.

Using secrets.SystemRandom class, we can use all the functions of a random module .

. Before the secrets module, we were using random.SystemRandom class to cryptographically secure random data. The same class is also accessible using the secrets module. Just execute secrets.SystemRandom() .

Let see the example of how to use secrets.SystemRandom class to secure the random generator.

import secrets print("Random integer numbers generated using secrets module ") #Getting systemRandom class instance out of secrets module secretsGenerator = secrets.SystemRandom() #random integer number uisng secrets randomNumber = secretsGenerator.randint(0,50) print("Secure random number is ", randomNumber) #random integer number within given range using secrets randomNumber = secretsGenerator.randrange(4, 40, 4) print("Secure random number within range is ", randomNumber) #Secure Random choice using secrets number_list = [6, 12, 18, 24, 30, 36, 42, 48, 54, 60] secure_choice = secretsGenerator.choice(number_list) print ("Secure random choice using secrets is ", secure_choice) #Secure Random sample uisng secrets secure_sample = secretsGenerator.sample(number_list, 3) print ("Secure random sample using secrets is ", secure_sample) #Secure Random uniform using secrets secure_float = secretsGenerator.uniform(2.5, 25.5) print("Secure random float number using secrets is ", secure_float)

Output:

Secure random number is 35 Secure random number within range is 28 Secure random choice using secrets is 54 Secure random sample using secrets is [30, 54, 60] Secure random float number using secrets is 11.52975639443349

Python Secrets Module Functions

The Secrets module uses the secure random source of the underlying operating system. Let see how to use secrets module functions.

secrets.randbelow(n)

Use the secrets.randbelow function to generate a secure integer number .

function . This function returns a secure random integer in the range [0, n). Here n is the exclusive upper bound.

0 is the starting number in the range, and n is the last number.

For example, secrets.randbelow(10) generate a single random number from 0 to 9.

Example:

import secrets print("Random integer number generated using secrets module is ") for i in range(3): print( secrets.randbelow(10), end =', ')

Output:

Random integer number generated using secrets module is 7, 3, 2,

secrets.choice(sequence)

This method returns a secure randomly-chosen element from a non-empty sequence. Here sequence can be list or string.

Example:

import secrets name = "GuidoVanRossum" print("secrets choice from string is ", secrets.choice(name)) name_list = ["Guido Van Rossum", "Bjarne Stroustrup", "Dennis Ritchie"] print("secrets choice from list is ", secrets.choice(name_list))

Output:

secrets choice from string is o secrets choice from list is Guido Van Rossum

secrets.randbits(k)

This method returns a secure unsigned integer with k random bits.

with k random bits. This function is to generate a random bitmask that would contain N bits set (this is not the same as generating a random integer since that is not guaranteed to have N bits set in it).

A random number generated using randbits is more secure.

It generates a random integer within a bit range.

If k=4 then Unsigned integer From 0 to 15.

k=8 then Unsigned integer From 0 to 255.

If k=16 then Unsigned integer From 0 to 65,535, and so on.

Let’s see the example :

import secrets for i in range(3): randomBitNumber = secrets.randbits(4) print("Random Number using 4 bit is",randomBitNumber ) for i in range(3): randomBitNumber = secrets.randbits(8) print("Random Number using 8 bit is",randomBitNumber ) for i in range(3): randomBitNumber = secrets.randbits(16) print("Random Number using 16 bit is",randomBitNumber ) for i in range(3): randomBitNumber = secrets.randbits(32) print("Random Number using 32 bit is",randomBitNumber )

Output:

Random Number using 4 bit is 3 Random Number using 4 bit is 5 Random Number using 4 bit is 11 Random Number using 8 bit is 179 Random Number using 8 bit is 190 Random Number using 8 bit is 233 Random Number using 16 bit is 36823 Random Number using 16 bit is 24082 Random Number using 16 bit is 39181 Random Number using 32 bit is 3372867089 Random Number using 32 bit is 134143722 Random Number using 32 bit is 3810053956

Generate secure token using secrets module

The secrets module provides functions for generating the secure tokens which are useful for applications to generate reset password tokens and hard-to-guess URLs.

The secure module has the following functions to generate a secure token.

secrets.token_bytes ( [ nbytes=None ] )

Return a secure random byte string containing the number of bytes if n-bytes are not supplied a reasonable default gets used.

secrets.token_hex ( [ nbytes=None ] )

Return a secure random text string, in hexadecimal format. The string has n-bytes random bytes, each byte converted to two hex digits. If n-bytes are not supplied a reasonable default gets used.

secrets.token_urlsafe ( [ nbytes=None ] )

Return a secure random URL-safe text string, containing n-bytes random bytes. Use this method to generate secure hard-to-guess URLs.

Let see the example to generate secure tokens.

import secrets print("Generate a secure byte token", secrets.token_bytes(16)) print("Generate a secure hexadecimal token", secrets.token_hex(32)) passwordResetLink = "https://demo.com/customer/eric/reset=" passwordResetLink+=secrets.token_urlsafe(32) print("Generate a secure URL", passwordResetLink)

Output:

Generate a secure byte token b'&\x19H\xc0r{\xa5\xd6\x0b\xf5\xb2\x1d\xc6\xf6]0' Generate a secure hexadecimal token dd772eb0c11c4995c3c9db5a20a555c31d70547c30df31e818be7c7832bb44f1 Generate a secure URL https://demo.com/customer/eric/reset=GzWfp5xCcuFsnEUb9qqN_v94_XOx9hPwSGszdx4rNBk

How many bytes should tokens use

Tokens need to have sufficient randomness To secure against brute-force attacks and timing attacks. As per experts, 32 bytes (256 bits) of randomness is sufficient to secure against brute-force attacks. You should choose byte size as per your requirement.

Reduce timing attack using secrets.compare_digest(a, b)

To reduce the risk of timing attacks secrets module has the compare_digest(a, b) function. This function returns True if string a and b are equal, otherwise False to reduce the risk of timing attacks.

Practical Example of secrets module

Let see the example now. In this example, we are generating a temporary password and sending this password on a temporary hard-to-guess URL so the client can reset his password using this URL.

Generate a ten-character alphanumeric password with at least one lowercase character, at least one uppercase character, at least one digits and one special symbol.

Generate a temporary URL

Example:

import secrets import string stringSource = string.ascii_letters + string.digits + string.punctuation password = secrets.choice(string.ascii_lowercase) password += secrets.choice(string.ascii_uppercase) password += secrets.choice(string.digits) password += secrets.choice(string.punctuation) for i in range(6): password += secrets.choice(stringSource) char_list = list(password) secrets.SystemRandom().shuffle(char_list) password = ''.join(char_list) print ("Secure Password is ", password) print ("Reset password URL Link") SecureURL = "https://demo.com/user/jhon/reset=" SecureURL+=secrets.token_urlsafe(32) print(SecureURL)

Output:

Secure Password is r6DS)nzc*- Reset password URL Link https://demo.com/user/jhon/reset=BdXvTTm_GtVcVko0W4Qf8jyqj9gE5I8KkWOEerAkmrk

Next Steps

To practice what you learned in this article, I have created a Python random data generation Quiz and Exercise project.

Solve our Python Random data generation Quiz to test your random data generation concepts.

Solve the Python Random data generation Exercise to practice and master the random data generation techniques.

References: