Schwacher PRNG

OWASP-Kategorie: MASVS-CRYPTO: Cryptography

Übersicht

Ein Pseudozufallszahlengenerator (Pseudorandom Number Generator, PRNG) ist ein Algorithmus, der auf einem Startwert, dem sogenannten Seed , vorhersagbare Zahlenfolgen generiert. Eine von einem PRNG generierte Zahlenfolge hat ungefähr dieselben Eigenschaften wie eine echte Zufallszahlenfolge, ist aber schneller und weniger rechenintensiv zu erstellen.

Mit anderen Worten: PRNGs bieten im Hinblick auf die Gleichmäßigkeit der Entropieverteilung eine höhere Sicherheit als schwache Zufallszahlengeneratoren (z.B. java.math.Random), die echte Zufallszahlenfolgen nachahmen. Die Erzeugung echter Zufallszahlen erfordert spezielle Geräte und geht oft über den Rahmen der normalen Entwicklung hinaus. In diesem Dokument wird die Erzeugung echter Zufallszahlen nicht behandelt, sondern nur auf PRNGs eingegangen, da sie die Standardmethode sind.

Schwachstellen bei PRNGs treten auf, wenn Entwickler einen regulären PRNG für kryptografische Zwecke verwenden, anstatt einen kryptografisch sicheren PRNG (Cryptographically-Secure PRNG, CSPRNG). Für CSPRNGs gelten strengere Anforderungen. Wenn der Seed unbekannt ist, dürfen sie einem Angreifer nur einen unbedeutenden Vorteil bei der Unterscheidung einer Ausgabefolge von einer tatsächlichen Zufallsfolge verschaffen.

Angreifer können die generierte Zahlenfolge möglicherweise auch erraten, wenn vorhersagbare Seeds verwendet werden, um einen PRNG oder CSPRNG zu initialisieren. Das ist beispielsweise der Fall, wenn der Seed vom Entwickler fest codiert wurde. Der Angreifer kann den Seed erraten und so die vom PRNG generierte Ausgabe vorhersagen.

Auswirkungen

Wenn ein nicht kryptografisch sicherer PRNG in einem Sicherheitskontext wie der Authentifizierung verwendet wird, kann ein Angreifer die zufällig generierten Zahlen möglicherweise erraten und Zugriff auf vertrauliche Daten oder Funktionen erhalten.

Gegenmaßnahmen

Allgemein

java.security.SecureRandom

Empfohlen für Sicherheitsanwendungen. Wenn die Linux-Kernel-Version 5.17 oder höher ist oder das Blockieren des Threads akzeptabel ist, warten Sie, bis genügend Entropie angesammelt ist, bevor Sie die Zufallszahlen generieren (d.h. verwenden Sie /dev/random). Rufen Sie dazu getInstanceStrong() auf:

Kotlin

val rand = SecureRandom.getInstanceStrong()

Java

SecureRandom rand = SecureRandom.getInstanceStrong();

Andernfalls sollte bei Linux-Kernelversionen vor 5.17, wenn das Blockieren des Threads beim Generieren von Zufallszahlen nicht akzeptabel ist, der Konstruktor SecureRandom direkt aufgerufen werden:

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 ruft den Standardsamen aus /dev/urandom ab und wird automatisch verwendet, wenn das Objekt erstellt oder abgerufen wird. Daher ist es nicht erforderlich, den PRNG explizit zu initialisieren. Im Allgemeinen wird von jeder deterministischen Verwendung von SecureRandom abgeraten, insbesondere wenn dies dazu führt, dass ein Seed-Wert fest codiert wird, der von jedem, der die App dekompiliert, eingesehen werden kann. Entwickler, die reproduzierbare pseudozufällige Ausgaben generieren möchten, sollten besser geeignete Primitive wie HMAC, HKDF und SHAKE verwenden.

java.util.Random

Vermeiden Sie die Verwendung für Sicherheits-/Authentifizierungszwecke. Für alle anderen Zwecke ist die Verwendung akzeptabel.

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

Ressourcen