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 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

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