Kategoria OWASP: MASVS-CRYPTO: Kryptografia
Przegląd
Pseudolosowy generator liczb (PRNG) to algorytm, który generuje przewidywalne sekwencje liczb na podstawie wartości początkowej zwanej ziarnem. Sekwencja liczb wygenerowana przez PRNG ma w przybliżeniu takie same właściwości jak prawdziwie losowa sekwencja liczb, ale jest szybsza i mniej kosztowna obliczeniowo.
Innymi słowy, PRNG zapewniają większą pewność niż słabe generatory liczb losowych (np. java.math.Random) pod względem równomierności rozkładu entropii, która naśladuje prawdziwie losowe sekwencje liczb. Generowanie prawdziwie losowych liczb wymaga specjalistycznego sprzętu i często wykracza poza zakres normalnego procesu tworzenia oprogramowania. Ten dokument nie obejmuje generowania prawdziwie losowych liczb i skupia się tylko na PRNG, ponieważ są one standardową metodologią.
Luki w zabezpieczeniach słabych PRNG występują, gdy deweloperzy używają zwykłego PRNG do celów kryptograficznych zamiast kryptograficznie bezpiecznego PRNG (CSPRNG). CSPRNG mają bardziej rygorystyczne wymagania, a gdy ziarno jest nieznane, muszą dawać atakującemu tylko nieznaczny przewagę w odróżnianiu sekwencji wyjściowej od rzeczywistej sekwencji losowej.
Atakujący mogą też odgadnąć wygenerowaną sekwencję liczb, gdy do zainicjowania PRNG lub CSPRNG używane są przewidywalne ziarna, np. zakodowane na stałe przez dewelopera. Atakujący może odgadnąć ziarno, a tym samym przewidzieć dane wyjściowe wygenerowane przez PRNG.
Wpływ
Jeśli w kontekście bezpieczeństwa, np. w przypadku uwierzytelniania, używany jest PRNG, który nie jest kryptograficznie bezpieczny, atakujący może odgadnąć losowo wygenerowane liczby i uzyskać dostęp do uprzywilejowanych danych lub funkcji.
Środki zaradcze
Ogólne
- Użyj
java.security.SecureRandom, gdy występują implikacje związane z bezpieczeństwem - W innych przypadkach używaj
java.util.Random - Nigdy nie używaj
Math.random!
java.security.SecureRandom
Zalecane do celów związanych z bezpieczeństwem. Jeśli wersja jądra systemu Linux to 5.17 lub nowsza albo blokowanie wątku jest dopuszczalne, przed wygenerowaniem liczb losowych poczekaj, aż zgromadzi się wystarczająca ilość entropii (czyli użyj /dev/random). Aby to zrobić, wywołaj getInstanceStrong():
Kotlin
val rand = SecureRandom.getInstanceStrong()
Java
SecureRandom rand = SecureRandom.getInstanceStrong();
W przeciwnym razie, w przypadku wersji jądra systemu Linux starszych niż 5.17, gdy blokowanie wątku podczas generowania liczb losowych jest niedopuszczalne, należy bezpośrednio wywołać konstruktor 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 pobiera domyślne ziarno z /dev/urandom i jest używany automatycznie, gdy obiekt jest tworzony lub pobierany, więc nie trzeba jawnie inicjować PRNG. Ogólnie rzecz biorąc, odradza się deterministyczne używanie SecureRandom (zwłaszcza jeśli prowadzi to do zakodowania na stałe wartości ziarna, którą każdy może zobaczyć po dekompilacji aplikacji). Deweloperzy, którzy chcą generować powtarzalne pseudolosowe dane wyjściowe, powinni używać bardziej odpowiednich elementów pierwotnych, takich jak HMAC, HKDF i SHAKE.
java.util.Random
Unikaj używania do celów związanych z bezpieczeństwem lub uwierzytelnianiem. W innych przypadkach jest to dopuszczalne.
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);
}
}
Zasoby
- java.security.SecureRandom
- java.util.Random
- Math.random
- CWE dotyczące przewidywalnego ziarna
- CWE dotyczące kryptograficznie słabego PRNG
- Java Secure Random
- Java Random a SecureRandom
- Jak używać SecureRandom
- Wskazówki dotyczące bezpieczeństwa PRNG w Pythonie
- Ściągawka OWASP dotycząca przechowywania kryptograficznego
- CVE-2013-6386: luka w zabezpieczeniach słabego PRNG w Drupalu
- CVE-2006-3419: luka w zabezpieczeniach słabego PRNG w Torze
- CVE-2008-4102: przewidywalne ziarno w Joomli
- Poprawka losowa jądra systemu Linux