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 circa 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 offrono maggiori garanzie rispetto agli 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
attrezzature 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à 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 malintenzionato solo un vantaggio insignificante nel differenziare una sequenza di output da una sequenza casuale effettiva.
Gli autori degli attacchi potrebbero anche essere in grado di indovinare la sequenza di numeri generata quando vengono utilizzati seed prevedibili, ad esempio quelli hardcoded dallo sviluppatore, per inizializzare un PRNG o CSPRNG, in quanto l'autore dell'attacco può indovinare il seed e quindi prevedere l'output generato dal PRNG.
Impatto
Se viene utilizzato un PRNG non sicuro dal punto di vista crittografico in un contesto di sicurezza come l'autenticazione, un malintenzionato potrebbe essere in grado di indovinare i numeri generati in modo casuale e ottenere l'accesso a dati o funzionalità privilegiati.
Mitigazioni
Generale
- Utilizza
java.security.SecureRandomquando ci sono implicazioni per la sicurezza - Utilizza
java.util.Randomper tutti gli altri casi. - Non utilizzare
Math.random.
java.security.SecureRandom
Consigliato per usi di sicurezza. Se la versione kernel Linux è 5.17+ o
il blocco del thread è accettabile, attendi che si accumuli entropia sufficiente prima di
generare i numeri casuali (ad es. utilizza /dev/random). Per farlo, 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 valore predefinito da /dev/urandom e viene utilizzato automaticamente quando l'oggetto viene costruito o ottenuto, quindi non è necessario inizializzare esplicitamente il PRNG. In generale, è sconsigliato qualsiasi utilizzo deterministico di SecureRandom (soprattutto se ciò comporta la codifica hardcoded di un valore di inizializzazione, che
chiunque decompili l'app può vedere). Gli sviluppatori che vogliono generare
un output pseudocasuale riproducibile devono utilizzare primitive più appropriate come
HMAC, HKDF e SHAKE.
java.util.Random
Evita per motivi di sicurezza / autenticazione, accettabile per qualsiasi altro utilizzo.
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
- CWE PRNG crittograficamente debole
- Java Secure Random
- Java Random e SecureRandom
- Come utilizzare SecureRandom
- Guida alla sicurezza PRNG di Python
- OWASP Cryptographic Storage Cheat Sheet
- CVE-2013-6386: Vulnerabilità PRNG debole in Drupal
- CVE-2006-3419: Vulnerabilità PRNG debole in Tor
- CVE-2008-4102: Predictable Seed in Joomla
- Patch casuale del kernel Linux