Insecure Random Number Vulnerability and Mitigation

Insecure Random Number Vulnerability and Mitigation

1. Vulnerability Description
Insecure random number vulnerability occurs when developers, in scenarios requiring the generation of random values (such as generating tokens, password reset links, encryption keys, etc.), use predictable or weak random number generators. This allows attackers to infer the random values, thereby bypassing authorization, hijacking sessions, or forging data. For example, using timestamps or simple algorithms as "random sources" is a typical mistake.

2. Vulnerability Principles and Risk Scenarios

  • Weak Random Number Generators:
    • Such as rand() in C/C++, rand() in PHP, or the Random class in Java. These pseudorandom number generators (PRNGs) rely on fixed seeds (e.g., system time). If attackers know the seed or part of the output, they can deduce subsequent random numbers.
    • Example: If rand() is used to generate a 6-digit verification code and the seed is the current second, attackers can try common timestamps to cover the possible range.
  • Insufficient Entropy Source:
    • In cryptographic scenarios, random numbers require sufficient entropy (randomness source). If the system's entropy pool is insufficient (e.g., just after a virtual machine boots), it may cause random numbers to repeat or exhibit strong patterns.
  • Risk Scenarios:
    • If critical data such as password reset tokens, CSRF tokens, or Session IDs are predictable, attackers can directly tamper with other users' accounts or perform unauthorized operations.

3. Vulnerability Verification Methods

  • Black-box Testing:
    • Collect multiple generated random values (e.g., obtaining 10 consecutive verification codes) and analyze patterns in their distribution or attempt to crack the generation algorithm.
    • Check if random values contain easily guessable information such as timestamps or user IDs.
  • Code Audit:
    • Search for random number generation functions in the code (e.g., Math.random(), Random.nextInt()), and confirm whether cryptographically secure alternatives are used.

4. Security Mitigation Measures

  • Use Cryptographically Secure Pseudorandom Number Generators (CSPRNG):
    • Java: Use java.security.SecureRandom instead of the Random class.
    • Python: Use os.urandom() or the secrets module (e.g., secrets.token_urlsafe()).
    • PHP: Use random_int() instead of rand().
  • Ensure Sufficient Entropy Source:
    • On Linux systems, obtain high-entropy random numbers from /dev/random or /dev/urandom (the latter does not block when entropy is insufficient and is more suitable for non-cryptographic scenarios).
  • Avoid Exposing the Random Seed:
    • Do not use easily guessable values such as time or user input as seeds.
  • Random Value Length and Complexity:
    • Important tokens should be at least 16 bytes in length and include a mix of alphanumeric and symbolic characters.

5. Practical Case Study
A system used the following code to generate password reset tokens:

// Vulnerable Code
$token = rand(100000, 999999); // 6-digit number, based on a time seed

The attacker discovered through multiple requests that tokens consistently started with 1xx, deduced the system used a fixed time range as the seed, and successfully brute-forced the administrator's password reset.

Fixed Code:

// Secure Code
$token = bin2hex(random_bytes(16)); // Generate a 32-character hexadecimal random number

6. Extended Considerations

  • In distributed systems, if multiple nodes use the same seed or a low-entropy source, random number conflicts may occur. Centralized random number services or hardware entropy sources (such as TPM) should be introduced.
  • For scenarios like verification codes, besides using random numbers, mechanisms such as rate limiting and lockouts after multiple failures should be combined to defend against brute-force attacks.