PRNG fraco

Categoria do OWASP: MASVS-CRYPTO - Criptografia

Visão geral

Um gerador de números pseudoaleatórios (PRNG, na sigla em inglês) é um algoritmo que gera sequências de números previsíveis com base em um valor inicial chamado de seed. Uma sequência de números gerada pelo PRNG tem aproximadamente as mesmas propriedades que uma sequência de números realmente aleatória, mas é mais rápida e mais fácil de criar.

Em outras palavras, os PRNGs têm garantias maiores do que RNGs fracos (por exemplo, java.math.Random) em termos de uniformidade de distribuição de entropia, o que emula sequências de números realmente aleatórias. A geração de números realmente aleatórios exige equipamentos especializados e geralmente está fora do escopo do desenvolvimento normal. Este documento não aborda a geração de números realmente aleatórios e se concentra apenas em PRNGs, já que eles são a metodologia padrão em uso.

Vulnerabilidades de PRNG fraco ocorrem quando os desenvolvedores usam um PRNG comum para fins criptográficos, em vez de um PRNG criptograficamente seguro (CSPRNG). Os CSPRNGs têm requisitos mais rigorosos e, quando a seed é desconhecida, eles dão a um invasor apenas uma vantagem insignificante em diferenciar uma sequência de saída de uma sequência aleatória real.

Os invasores também podem adivinhar a sequência numérica quando seeds previsíveis (como as fixadas no código pelo desenvolvedor) são usadas para inicializar um PRNG ou CSPRNG, porque o invasor pode adivinhar a seed e, portanto, prever a saída gerada pelo PRNG.

Impacto

Se um PRNG não criptograficamente seguro for usado em um contexto de segurança, como autenticação, o invasor poderá adivinhar os números gerados aleatoriamente e ter acesso a dados ou recursos privilegiados.

Mitigações

Geral

java.security.SecureRandom

Recomendado para usos de segurança. Se a versão do kernel do Linux for 5.17 ou mais recente ou o bloqueio da linha de execução for aceitável, aguarde até que haja entropia suficiente para gerar os números aleatórios (por exemplo, use /dev/random). Para fazer isso, chame getInstanceStrong():

Kotlin

val rand = SecureRandom.getInstanceStrong()

Java

SecureRandom rand = SecureRandom.getInstanceStrong();

Caso contrário, em versões do kernel do Linux anteriores à versão 5.17, quando o bloqueio da linha de execução for inaceitável ao gerar números aleatórios, o construtor SecureRandom deverá ser chamado diretamente:

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

O SecureRandom recebe a seed padrão de /dev/urandom e é usado automaticamente quando o objeto é construído ou recebido. Não é necessário propagar explicitamente o PRNG. Em geral, não recomendamos o uso determinístico de SecureRandom (especialmente se isso levar à codificação de um valor de seed, que qualquer pessoa que descompilar o app pode encontrar). Os desenvolvedores que querem gerar uma saída pseudoaleatória reproduzível precisam usar primitivos mais apropriados, como HMAC, HKDF e SHAKE.

java.util.Random

Evite para fins de segurança / autenticação; aceitável para qualquer outro uso.

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

Recursos