Try the Random String Generator

Secure Randomness: Why Math.random() Fails for Security Tokens β€” and the Right Alternatives

Math.random() in JavaScript is predictable from 128 observations. Python's random module explicitly warns it's not for security. Here's why PRNGs fail for tokens, the secure alternatives in every major language, and the specific bit lengths needed for different security contexts.

By sadiqbd Β· June 9, 2026

Share:
Secure Randomness: Why Math.random() Fails for Security Tokens β€” and the Right Alternatives

Math.random() is fine for a dice roll β€” and disastrous for a session token

The distinction between a pseudorandom number generator (PRNG) and a cryptographically secure pseudorandom number generator (CSPRNG) is one of those security concepts that sounds pedantic until you see what happens when developers use the wrong one.

A PRNG produces sequences that appear random but are deterministic from their seed. Given a small number of observations, the internal state can often be reconstructed, and future values predicted. A CSPRNG produces sequences that are computationally infeasible to predict, using entropy from the operating system.

This difference is irrelevant for games, simulations, and statistical sampling. It's critical for security tokens, passwords, cryptographic keys, and session identifiers.


How common PRNGs fail for security

JavaScript: Math.random()

Math.random() in V8 (Chrome/Node.js) uses xorshift128+, a fast non-cryptographic PRNG. Security researchers have demonstrated that given 128 consecutive Math.random() outputs, the internal state can be fully recovered, enabling prediction of all future values.

// Common mistake: using Math.random() for token generation
function generateToken() {
    return Math.random().toString(36).substr(2, 32);
    // 32 chars but ~90 bits of real entropy, and PREDICTABLE
}

If an attacker can observe several tokens generated by the same server instance (perhaps through a public-facing feature), they may be able to predict future tokens generated in the same process.

PHP: rand() and mt_rand()

rand() uses the C library's rand(), which varies by platform and is not cryptographically secure. mt_rand() uses Mersenne Twister, which is better but still not cryptographically secure β€” the internal state can be recovered from 624 consecutive outputs.

Python: random module

random.random() uses Mersenne Twister β€” fast, good statistical properties, not cryptographically secure. Python's documentation explicitly states: "Warning: The pseudo-random generators of this module should not be used for security purposes."


The secure alternatives

JavaScript/Node.js

// Node.js - built-in crypto module
const crypto = require('crypto');

// Generate 32 bytes of random data as hex string (64 chars)
const token = crypto.randomBytes(32).toString('hex');

// As URL-safe base64
const tokenBase64 = crypto.randomBytes(32).toString('base64url');

// Browser: Web Crypto API
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const token = Array.from(array, b => b.toString(16).padStart(2, '0')).join('');

// Or using webcrypto in Node 15+
const { randomBytes } = require('crypto');
const token = randomBytes(32).toString('hex');

Python

import secrets
import string

# Generate 32 bytes as hex string
token = secrets.token_hex(32)

# URL-safe base64
token_b64 = secrets.token_urlsafe(32)

# Random integer in range [0, max)
n = secrets.randbelow(100)

# Secure password from character set
alphabet = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(alphabet) for _ in range(24))

The secrets module (Python 3.6+) was added specifically to provide a single, obviously-correct API for cryptographic randomness. Use it for anything security-related.

PHP

// PHP 7+ - built-in CSPRNG
$token = bin2hex(random_bytes(32));       // 64 hex chars
$token = base64_encode(random_bytes(32)); // 44 base64 chars

// Random integer in range
$n = random_int(1, 100);

random_bytes() and random_int() were added in PHP 7 as the secure counterparts to rand() and mt_rand().

Ruby

require 'securerandom'

token = SecureRandom.hex(32)       # 64 hex chars
token = SecureRandom.base64(32)    # base64
token = SecureRandom.urlsafe_base64(32)  # URL-safe base64
token = SecureRandom.uuid          # UUID v4

Java

import java.security.SecureRandom;
import java.util.Base64;

SecureRandom random = new SecureRandom();
byte[] bytes = new byte[32];
random.nextBytes(bytes);
String token = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);

SecureRandom in Java automatically seeds from the OS entropy source and uses a CSPRNG algorithm.


How CSPRNGs get their entropy

CSPRNGs derive their seed from the operating system's entropy pool, which collects randomness from hardware events:

  • /dev/urandom (Linux): reads from the kernel entropy pool, which gathers entropy from disk I/O timing, network packet timing, keyboard and mouse events, CPU thermal noise
  • CryptGenRandom (Windows): similar OS-level entropy gathering
  • Hardware RNG (RDRAND on x86): CPUs with hardware random number generators provide entropy directly from thermal noise in transistors

Modern OS entropy pools are generally considered sufficient for most security applications, even on newly booted virtual machines. Historical concerns about insufficient entropy on VMs have been largely addressed by virtio-rng and other paravirtual entropy sources.


Token length recommendations revisited

With a CSPRNG producing truly random output:

Token use Recommended bits Hex string length URL-safe base64
Session token 128 bits 32 chars 22 chars
CSRF token 128 bits 32 chars 22 chars
API key 256 bits 64 chars 43 chars
Password reset token 256 bits 64 chars 43 chars
Long-lived secret 256 bits 64 chars 43 chars

These assume the token is generated with a CSPRNG. A PRNG-generated token provides far less effective security than these bit counts suggest.


How to use the Random String Generator on sadiqbd.com

  1. Set the length β€” choose based on the bit count you need (above)
  2. Select the character set β€” hex for most developer use cases; alphanumeric for user-readable tokens
  3. Generate β€” the tool uses a cryptographically secure source
  4. Copy β€” paste directly into your application

Frequently Asked Questions

How do I know if a library's random function is secure? Check the documentation for explicit security language. Python's secrets module documentation says "suitable for managing data such as passwords, account authentication, security tokens." The random module documentation says "not suitable for security or cryptographic purposes." PHP's random_bytes() and random_int() documentation notes "Generates cryptographically secure pseudo-random bytes."

Is UUID v4 a CSPRNG output? UUID v4 is 122 bits of random data. Whether those bits are cryptographically random depends on how the UUID is generated. Python's uuid.uuid4() uses os.urandom() (cryptographically secure). JavaScript's crypto.randomUUID() uses the Web Crypto API (secure). However, some older UUID v4 implementations have used non-secure sources. Verify the source, not just the function name.

Is the Random String Generator free? Yes β€” completely free, no sign-up required.


The security of a token is only as good as the randomness used to generate it. Using Math.random() for a session token is a common mistake that produces tokens that look secure but are predictable to a determined attacker.

Try the Random String Generator free at sadiqbd.com β€” generate cryptographically secure random strings at any length and character set.

Share:
Try the related tool:
Open Random String Generator

More Random String Generator articles