Skillversitas

Secure Random Numbers

Python has two random number families, and mixing them up is a classic security bug: random is a fast Mersenne Twister for simulation and games, while secrets (and os.urandom) is a cryptographically secure source for anything an attacker could observe. The MT19937 state can be reconstructed from about 624 consecutive outputs, so a session token built on random is predictable - a real vulnerability, not a theoretical one.

The secrets Module

import secrets

secrets.token_bytes(32)          # 32 raw bytes - keys, IVs, salts
secrets.token_hex(16)            # 32-character hex string
secrets.token_urlsafe(24)        # URL-safe base64 - session tokens, reset links
secrets.choice([1, 2, 3, 4])     # uniform pick, no modulo bias
secrets.randbelow(100)           # uniform int in [0, 100)

Everything here draws from the OS entropy source (getrandom, /dev/urandom on Unix). There is no seeding: no seed(), no reproducibility - which is exactly what you want from security values.

os.urandom

import os

iv = os.urandom(16)         # AES-CBC IV
nonce = os.urandom(12)      # GCM nonce
salt = os.urandom(16)       # KDF salt

os.urandom(n) is the raw primitive that secrets wraps; use it when you want bytes for a specific construction. secrets.SystemRandom() exposes the same source as a random.Random-compatible object.

What Is Not for Security

SourceUse forNot for
random.random()simulation, shuffling test data, gamestokens, keys, IVs
time-based seedsnever for securityanything guessable
uuid.uuid4()identifiers (wraps os.urandom)keys - treat it as an ID
secrets.*keys, nonces, tokens, passwordsdeterministic tests (seed those elsewhere)

Constant-Time Comparison

Generating secure values is half the job; comparing them without leaking timing is the other half:

import secrets

provided = "k9xQ..."        # e.g. from a cookie or header
expected = "k9xQ..."        # the token you issued
secrets.compare_digest(provided.encode(), expected.encode())   # True/False

compare_digest runs in time independent of where the first mismatch is, closing the timing channel that a plain == leaves open on tokens and MACs.

Summary

The rule of thumb: if an attacker could profit from guessing the value, it comes from secrets or os.urandom - tokens, nonces, IVs, salts, keys, password resets. Keep random for math and games, and compare secrets with compare_digest.