Categoria do OWASP: MASVS-CRYPTO - Criptografia
Visão geral
Um gerador de números pseudoaleatórios (PRNG) é um algoritmo que gera sequências de números previsíveis com base em um valor inicial chamado de semente. 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 menos custosa 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 verdadeiramente aleatórias. A geração de números verdadeiramente aleatórios requer
equipamentos especializados e, muitas vezes, está fora do escopo de desenvolvimento normal. Isso
documento não aborda a geração de números realmente aleatórios e se concentra apenas em
Os PRNGs 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 semente é desconhecida, eles precisam dar para um invasor só uma vantagem insignificante em diferenciar uma 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
- Use
java.security.SecureRandom
quando houver implicações de segurança - Use
java.util.Random
para outros casos - Nunca use
Math.random
.
java.security.SecureRandom
Recomendado para usos de segurança. Se a versão do kernel do Linux for 5.17+ ou
bloquear a linha de execução é aceitável, aguarde até que haja entropia suficiente acumular antes
você gera os números aleatórios (ou seja, usa /dev/random
). Para 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 não pode ocorrer ao gerar números aleatórios, você pode chamar o construtor SecureRandom
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
}
}
SecureRandom
recebe a semente padrão de /dev/urandom
e é automaticamente
usada quando o objeto é construído ou obtido, portanto, não há necessidade de
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 uso outros.
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
- java.security.SecureRandom
- java.util.Random
- Math.random
- CWE de seed previsível (em inglês)
- CWE PRNG criptograficamente fraco (em inglês)
- Java Secure Random (em inglês)
- Java Random versus SecureRandom
- Como usar o SecureRandom (em inglês)
- Orientação de segurança de PRNG para Python (em inglês)
- Folha de referência do armazenamento criptográfico OWASP (em inglês)
- CVE-2013-6386: vuln PRNG fraco em Drupal (em inglês)
- CVE-2006-3419: vuln PRNG fraco em Tor (em inglês)
- CVE-2008-4102: seed previsível em Joomla (em inglês)
- Patch aleatório do kernel do Linux (em inglês)