Categoria OWASP: MASVS-CRYPTO: Cryptography
Panoramica
Un generatore di numeri pseudocasuali (PRNG) è un algoritmo che genera sequenze di numeri prevedibili in base a un valore iniziale chiamato seme. Una sequenza di numeri generata da un PRNG ha approssimativamente le stesse proprietà di una sequenza di numeri veramente casuali, ma è più veloce e meno costosa dal punto di vista computazionale da creare.
In altre parole, i PRNG hanno garanzie più elevate rispetto ai RNG deboli (ad es. java.math.Random) in termini di uniformità della distribuzione dell'entropia, che emulano sequenze di numeri veramente casuali. La generazione di numeri veramente casuali richiede apparecchiature specializzate e spesso non rientra nell'ambito dello sviluppo normale. Questo documento non tratta la generazione di numeri veramente casuali e si concentra solo sui PRNG, in quanto sono la metodologia standard in uso.
Le vulnerabilità dei PRNG deboli si verificano quando gli sviluppatori utilizzano un PRNG normale per scopi crittografici, anziché un PRNG crittograficamente sicuro (CSPRNG). I CSPRNG hanno requisiti più rigorosi e, quando il seme è sconosciuto, devono dare a un utente malintenzionato solo un vantaggio insignificante nel distinguere una sequenza di output da una sequenza casuale effettiva.
Gli utenti malintenzionati potrebbero anche essere in grado di indovinare la sequenza di numeri generata quando vengono utilizzati semi prevedibili, come quelli codificati in modo rigido dallo sviluppatore, per inizializzare un PRNG o un CSPRNG, in quanto l'utente malintenzionato può indovinare il seme e quindi prevedere l'output generato dal PRNG.
Impatto
Se in un contesto di sicurezza come l'autenticazione viene utilizzato un PRNG non crittograficamente sicuro, un utente malintenzionato potrebbe essere in grado di indovinare i numeri generati in modo casuale e ottenere l'accesso a dati o funzionalità privilegiati.
Mitigazioni
Generali
- Utilizza
java.security.SecureRandomquando sono presenti implicazioni per la sicurezza - Utilizza
java.util.Randomper tutti gli altri casi - Non utilizzare mai
Math.random!
java.security.SecureRandom
Consigliato per gli usi di sicurezza. Su Android, SecureRandom.getInstanceStrong() è equivalente all'ottenimento di un SHA1PRNG da AndroidOpenSSL. Non esegue il mapping a un'implementazione di blocco /dev/random. Per utilizzarlo, chiama getInstanceStrong():
Kotlin
val rand = SecureRandom.getInstanceStrong()
Java
SecureRandom rand = SecureRandom.getInstanceStrong();
In caso contrario, nelle versioni del kernel Linux precedenti alla 5.17, quando il blocco del thread è inaccettabile durante la generazione di numeri casuali, è necessario chiamare direttamente il costruttore SecureRandom:
Kotlin
import java.security.SecureRandom
object generateRandom {
@JvmStatic
fun main(args: Array<String>) {
// Create instance of SecureRandom class
val rand = SecureRandom()
// Generate random integers in range 0 to 999
val rand_int = rand.nextInt(1000)
// Use rand_int for security & authentication
}
}
Java
import java.security.SecureRandom;
public class generateRandom {
public static void main(String args[])
{
// Create instance of SecureRandom class
SecureRandom rand = new SecureRandom();
// Generate random integers in range 0 to 999
int rand_int = rand.nextInt(1000);
// Use rand_int for security & authentication
}
}
SecureRandom ottiene il seme predefinito da /dev/urandom e viene utilizzato automaticamente quando l'oggetto viene costruito o ottenuto, quindi non è necessario seminare esplicitamente il PRNG. In generale, è sconsigliato qualsiasi utilizzo deterministico di SecureRandom (soprattutto se ciò comporta la codifica rigida di un valore di seme, che chiunque decompili l'app può vedere). Gli sviluppatori che vogliono generare output pseudocasuali riproducibili devono utilizzare primitive più appropriate come HMAC, HKDF e SHAKE.
java.util.Random
Evita per scopi di sicurezza / autenticazione, accettabile per qualsiasi altro scopo.
Kotlin
import java.util.Random
object generateRandom {
@JvmStatic
fun main(args: Array<String>) {
// Create instance of SecureRandom class
val rand = Random()
// Generate random integers in range 0 to 999
val rand_int = rand.nextInt(1000)
}
}
Java
import java.util.Random;
public class generateRandom {
public static void main(String args[])
{
// Create instance of Random class
Random rand = new Random();
// Generate random integers in range 0 to 999
int rand_int = rand.nextInt(1000);
}
}
Risorse
- java.security.SecureRandom
- java.util.Random
- Math.random
- Predictable Seed CWE
- Cryptographically Weak PRNG CWE
- Java Secure Random
- Java Random versus SecureRandom
- How to use SecureRandom
- Python PRNG security guidance
- OWASP Cryptographic Storage Cheat Sheet
- CVE-2013-6386: Weak PRNG vuln in Drupal
- CVE-2006-3419: Weak PRNG vuln in Tor
- CVE-2008-4102: Predictable Seed in Joomla
- Linux Kernel random patch