Слабый генератор псевдослучайных чисел

Категория OWASP: MASVS-CRYPTO: криптография

Обзор

Генератор псевдослучайных чисел (ГПСЧ) – это алгоритм, который генерирует предсказуемые последовательности чисел на основе начального значения, называемого начальным числом. Последовательность чисел, сгенерированная ГПСЧ, имеет примерно те же свойства, что и последовательность истинно случайных чисел, но создается быстрее и требует меньше вычислительных ресурсов.

Другими словами, ГПСЧ обеспечивают более высокую надежность, чем слабые ГСЧ (например, java.math.Random), с точки зрения равномерности распределения энтропии, которая имитирует истинно случайные последовательности чисел. Для генерации по-настоящему случайных чисел требуется специализированное оборудование, которое обычно не используется при разработке. В этом документе не рассматривается генерация истинно случайных чисел. Мы сосредоточимся на ГПСЧ, поскольку они являются стандартной методологией.

Уязвимости, связанные со слабыми генераторами псевдослучайных чисел, возникают, когда разработчики используют обычные генераторы вместо криптографически защищенных. К CSPRNG предъявляются более строгие требования. Если начальное значение неизвестно, злоумышленник должен иметь лишь незначительное преимущество в дифференциации выходной последовательности от фактической случайной последовательности.

Злоумышленники также могут угадать сгенерированную последовательность чисел, если для инициализации PRNG или CSPRNG используются предсказуемые начальные значения, например заданные разработчиком в коде. В этом случае злоумышленник может угадать начальное значение и, следовательно, предсказать выходные данные, сгенерированные PRNG.

Влияние

Если в контексте безопасности, например при аутентификации, используется криптографически небезопасный генератор псевдослучайных чисел, злоумышленник может угадать случайно сгенерированные числа и получить доступ к конфиденциальным данным или функциям.

Предотвращение атак

Общие

java.security.SecureRandom

Рекомендуется для обеспечения безопасности. На Android SecureRandom.getInstanceStrong() эквивалентно получению SHA1PRNG из AndroidOpenSSL. Она не сопоставляется с блокирующей реализацией /dev/random. Чтобы воспользоваться им, позвоните по номеру getInstanceStrong().

Kotlin

val rand = SecureRandom.getInstanceStrong()

Java

SecureRandom rand = SecureRandom.getInstanceStrong();

В противном случае в версиях ядра Linux до 5.17, когда блокировка потока при генерации случайных чисел недопустима, конструктор 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 получает начальное значение по умолчанию из /dev/urandom и автоматически используется при создании или получении объекта, поэтому нет необходимости явно задавать начальное значение для PRNG. В целом не рекомендуется использовать SecureRandom детерминированным образом (особенно если это приводит к заданию в коде начального значения, которое может увидеть любой, кто декомпилирует приложение). Разработчикам, которым нужно генерировать воспроизводимые псевдослучайные выходные данные, следует использовать более подходящие примитивы, такие как HMAC, HKDF и SHAKE.

java.util.Random

Не рекомендуется использовать для обеспечения безопасности и аутентификации. Подходит для любых других целей.

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

Ресурсы