PRNG debole

Categoria OWASP: MASVS-CRYPTO: crittografia

Panoramica

Un generatore di numeri pseudocasuali (PRNG) è un algoritmo che genera sequenze numeriche prevedibili basate su un valore iniziale chiamato seed. R Una sequenza numerica generata da PRNG ha approssimativamente le stesse proprietà di una sequenza numerica una sequenza di numeri casuale, ma è più veloce e meno costosa dal punto di vista del calcolo per creare.

In altre parole, le PRNG offrono garanzie superiori rispetto alle 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 casuali richiede apparecchiature specializzate e spesso non rientrano nell'ambito del normale sviluppo. Questo documento non tratta la generazione di numeri veramente casuali e si concentra solo su PRNG, in quanto rappresentano la metodologia standard in uso.

Le vulnerabilità PRNG deboli si verificano quando gli sviluppatori usano un PRNG normale per al posto di un PRNG con protezione crittografica (CSPRNG). I CSPRNG hanno requisiti più rigidi e, quando il seed è sconosciuto, devono fornire un aggressore è solo un vantaggio insignificante nel differenziare un output da una sequenza casuale effettiva.

Gli attaccanti potrebbero anche essere in grado di indovinare la sequenza di numeri generata quando vengono utilizzati semi prevedibili, ad esempio quelli hardcoded dallo sviluppatore, per inizializzare un generatore di numeri pseudo-casuali (PRNG) o un generatore di numeri pseudo-casuali basato su crittografia (CSPRNG), in quanto l'attaccante 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 generatore di numeri pseudocasuali non sicuro dal punto di vista della crittografia, un malintenzionato potrebbe essere in grado di indovinare i numeri generati in modo casuale e ottenere l'accesso a funzionalità o dati privilegiati.

Mitigazioni

Generali

java.security.SecureRandom

Consigliato per usi di sicurezza. Se la versione del kernel Linux è 5.17 o successiva o il blocco del thread è accettabile, attendi che si accumuli sufficiente entropia prima di generare i numeri casuali (ovvero utilizza /dev/random). Per farlo, chiama getInstanceStrong():

Kotlin

val rand = SecureRandom.getInstanceStrong()

Java

SecureRandom rand = SecureRandom.getInstanceStrong();

Altrimenti, nelle versioni del kernel Linux precedenti alla 5.17, quando il blocco del thread non accettabile quando si generano numeri casuali, allora il costruttore SecureRandom deve essere chiamato direttamente:

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 seed predefinito da /dev/urandom e viene automaticamente utilizzata quando l'oggetto viene creato o ottenuto, quindi non è necessario eseguire esplicitamente il seed del PRNG. In generale, qualsiasi utilizzo deterministico di SecureRandom è sconsigliato (soprattutto se porta alla codifica forzata di un valore seed, 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 cosa diverso.

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