Catégorie OWASP : MASVS-CRYPTO : cryptographie
Présentation
Un générateur de nombres pseudo-aléatoires (ou PRNG) est un algorithme qui génère des séquences de nombres prévisibles en fonction d'une valeur de départ appelée graine. Une séquence de nombres générés par un PRNG a presque les mêmes propriétés qu'une séquence de nombres véritablement aléatoires, mais est plus rapide et moins coûteuse en calcul à créer.
En d'autres termes, les PRNG ont des assurances plus élevées que les RNG faibles (par exemple, java.math.Random
) en termes d'uniformité de la distribution d'entropie, qui émulent des séquences de nombres véritablement aléatoires. La génération de nombres véritablement aléatoires nécessite des équipements spécialisés et sort souvent du champ d'application du développement normal. Cet article ne traite pas de la génération de nombres véritablement aléatoires. Il se concentre uniquement sur les PRNG, qui constituent la méthodologie standard utilisée.
Des failles de PRNG faible se produisent lorsque les développeurs utilisent un PRNG standard à des fins de chiffrement, plutôt qu'un CSPRNG, qui est sécurisé du point de vue cryptographique. Les exigences relatives aux CSPRNG sont plus strictes et, lorsque la valeur de graine n'est pas connue, ils ne doivent offrir aux pirates informatiques qu'un avantage insignifiant pour différencier une séquence de sortie d'une séquence aléatoire réelle.
Les pirates informatiques peuvent également deviner la séquence de nombres générés lorsque des graines prévisibles, telles que celles codées en dur par le développeur, sont utilisées pour initialiser la génération de nombres via un PRNG ou un CSPRNG, car ils peuvent deviner la graine et ainsi prédire la sortie générée par le PRNG.
Impact
Si un PRNG non sécurisé de manière cryptographique est utilisé dans un contexte de sécurité tel que l'authentification, un pirate informatique peut deviner les nombres générés aléatoirement et accéder à des données ou à des fonctionnalités privilégiées.
Stratégies d'atténuation
Général
- Utilisez
java.security.SecureRandom
en cas d'impact sur la sécurité. - Utilisez
java.util.Random
dans tous les autres cas. - N'utilisez jamais
Math.random
.
java.security.SecureRandom
Recommandé pour des raisons de sécurité. Si la version de noyau Linux est 5.17 ou une version ultérieure, ou si le blocage du thread est acceptable, attendez que l'entropie suffisante s'accumule avant de générer les nombres aléatoires (par exemple, utilisez /dev/random
). Pour ce faire, appelez getInstanceStrong()
:
Kotlin
val rand = SecureRandom.getInstanceStrong()
Java
SecureRandom rand = SecureRandom.getInstanceStrong();
Sinon, sur les versions de noyau Linux antérieures à la version 5.17 où le blocage du thread n'est pas acceptable lors de la génération de nombres aléatoires, le constructeur SecureRandom
doit être appelé directement :
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
obtient la valeur de graine par défaut à partir de /dev/urandom
et est automatiquement utilisé lorsque l'objet est construit ou obtenu. Il n'est donc pas nécessaire d'alimenter explicitement le PRNG. En règle générale, toute utilisation déterministe de SecureRandom est déconseillée (surtout si cela entraîne le codage en dur d'une valeur de graine, que toute personne décompilant l'application peut voir). Les développeurs qui souhaitent générer des résultats pseudo-aléatoires reproductibles doivent utiliser des primitives plus appropriées, telles que HMAC, HKDF, SHAKE, etc.
java.util.Random
À éviter à des fins de sécurité/d'authentification, mais acceptable dans d'autres circonstances.
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);
}
}