PRNG debole

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

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