Słaby PRNG

Kategoria OWASP: MASVS-CRYPTO: Kryptografia

Omówienie

Generator pseudorandomów (PRNG) to algorytm, który generuje przewidywalne sekwencje liczb na podstawie wartości początkowej nazywanej seedem. Sekwencja liczb wygenerowana przez PRNG ma w przybliżeniu te same właściwości co prawdziwa losowa sekwencja liczb, ale jej utworzenie jest szybsze i mniej kosztowne pod względem obliczeniowym.

Inaczej mówiąc, PRNG mają wyższe gwarancje niż słabe generatory liczb losowych (np. java.math.Random) pod względem równomierności rozkładu entropii, który emuluje naprawdę losowe ciągi liczbowe. Prawdziwe losowe generowanie liczb wymaga specjalistycznego sprzętu i często wykracza poza zakres normalnego rozwoju. Ten nie obejmuje generowania liczb losowych i skupia się tylko na PRNG, ponieważ są to standardowa metodologia używana.

Słabe luki w zabezpieczeniach PRNG występują, gdy deweloperzy używają zwykłego PRNG do do celów kryptograficznych, a nie do kryptograficznie bezpiecznych PRNG (CSPRNG). CSPRNG mają bardziej rygorystyczne wymagania, a w przypadku nieznanej wartości wyjściowej muszą podać nieistotnej przewagi w rozróżnieniu danych wyjściowych, z rzeczywistej sekwencji losowej.

Atakujący mogą też być w stanie odgadnąć wygenerowaną sekwencję liczb, gdy do zainicjowania generatora liczb pseudolosowych (PRNG) lub generatora liczb pseudolosowych z zabezpieczeniem CSPRNG używane są przewidywalne nasiona, np. zakodowane na stałe przez dewelopera, ponieważ atakujący może odgadnąć nasienie i w ten sposób przewidzieć dane wyjściowe wygenerowane przez generator liczb pseudolosowych.

Wpływ

Jeśli niezabezpieczony kryptograficznie klucz PRNG jest używany w kontekście zabezpieczeń, na przykład uwierzytelnianie, haker może odgadnąć losowo wygenerowane liczby, oraz uzyskać dostęp do uprzywilejowanych danych i funkcji.

Środki zaradcze

Ogólne

java.security.SecureRandom

Zalecany do celów związanych z bezpieczeństwem. Jeśli jądro Linux jest w wersji 5.17 lub nowszej lub zablokowanie wątku, poczekaj na nagromadzenie wystarczającej entropii przed generujesz liczby losowe (np. /dev/random). Aby to zrobić, zadzwoń: getInstanceStrong():

Kotlin

val rand = SecureRandom.getInstanceStrong()

Java

SecureRandom rand = SecureRandom.getInstanceStrong();

W innych wersjach jądra Linuxa, które są starsze niż 5.17, gdy blokowanie wątku jest niedopuszczalne podczas generowania liczb losowych, konstruktor SecureRandom powinien być wywoływany bezpośrednio:

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 pobiera domyślne dane wyjściowe z /dev/urandom i jest automatycznie stosowane używanej podczas tworzenia lub uzyskiwania obiektu, więc nie trzeba jawnie wywołuje PRNG. Ogólnie każde deterministyczne użycie funkcji SecureRandom (zwłaszcza wtedy, gdy doprowadzi to do zakodowania na stałe wartości wyjściowej, każdy użytkownik dekompilujący aplikację). Deweloperzy, którzy chcą generować odtwarzalne dane wyjściowe powinny używać bardziej odpowiednich elementów podstawowych, takich jak HMAC, HKDF i SHAKE.

java.util.Random

Unikaj stosowania w celu bezpieczeństwa lub uwierzytelniania, ale do innych celów jest ono dopuszczalne.

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);
    }
}

Materiały