Ratgeber · Algorithmus & Engine

crypto.getRandomValues vs Math.random: Was steckt hinter den Zufallsquellen?

Beide liefern Zufallszahlen, aber nur eine ist nicht vorhersagbar. Wir vergleichen Determinismus, Vorhersagbarkeit, Performance und schauen, wann welche Quelle die richtige ist.

7 Min Lesezeit 1.590 Wörter 5 FAQs
Mateusz Viola
Mateusz ViolaBetreiber & Zufalls-Tüftler
Geprüft am

Wenn dein Browser dir eine Zufallszahl liefert, kann er das auf zwei Wegen tun. Der ältere und bekanntere Weg ist Math.random(). Der jüngere und sicherere ist crypto.getRandomValues(). Beide haben ihren Platz, aber sie sind nicht austauschbar. Wer den Unterschied nicht kennt, wählt manchmal die falsche und merkt es nie, weil das Tool trotzdem läuft. Bei Spaß-Ziehungen ist das egal, bei echten Verlosungen weniger.

Was Math.random eigentlich macht

Math.random gibt eine Fließkommazahl zwischen 0 (inklusive) und 1 (exklusive) zurück. Was viele nicht wissen: Die Zahl ist nicht wirklich zufällig. Sie wird von einem Pseudo-Zufalls-Generator berechnet, der einen internen Zustand speichert und bei jedem Aufruf den nächsten Wert in einer langen, vorberechneten Sequenz zurückgibt.

In Chrome und Node.js läuft seit 2015 ein Algorithmus namens xorshift128+, der einen 128-Bit-Zustand pflegt und durch Bit-Verschiebungen und XOR-Operationen die nächste Zahl generiert. Die Sequenz hat eine Periode von 2^128 minus 1, also etwa 3,4 mal 10^38 Aufrufe, bevor sie sich wiederholt. Das ist mehr als die Anzahl der Atome im sichtbaren Universum, also praktisch unendlich für jeden vernünftigen Zweck.

Der entscheidende Punkt: Wenn jemand den internen Zustand des Generators kennt, kann er alle zukünftigen Zahlen vorhersagen. Und es gibt Forschungsarbeiten, die zeigen, dass man den Zustand aus relativ wenigen beobachteten Outputs rekonstruieren kann, wenn man mathematisch weiß, was man tut. Für eine Animation ist das irrelevant. Für ein Online-Casino wäre es ein Albtraum.

Was crypto.getRandomValues anders macht

crypto.getRandomValues ist die Browser-Schnittstelle zum kryptographisch sicheren Zufallsgenerator des Betriebssystems. Auf Linux liest das im Hintergrund aus /dev/urandom oder ruft den Syscall getrandom() auf. Auf Windows ist es BCryptGenRandom. Auf macOS getentropy. Alle drei haben gemeinsam, dass sie Entropie aus mehreren physikalischen Quellen mischen.

Was heißt physikalische Entropie? Quellen sind unter anderem: die Zeitabstände zwischen Tastenanschlägen, Mausbewegungen, Netzwerk-Interrupts, Festplatten-Zugriffe, Thermisches Rauschen von Halbleitern. Auf modernen Intel- und AMD-CPUs gibt es zusätzlich den RDRAND-Befehl, der direkt aus einem dedizierten Hardware-Zufalls-Modul liest, das ein Rauschen aus einer thermischen Quelle quantisiert. Diese Quellen sind nicht vorhersagbar, auch nicht mit perfektem Wissen über alle vergangenen Werte.

Die Web Crypto API ist seit Chrome 11, Firefox 21 und Safari 6 verfügbar, also seit über zehn Jahren in allen relevanten Browsern. Browser-Support ist kein Argument mehr, sie nicht zu nutzen.

Eigenschaft Math.random() crypto.getRandomValues() Determinismus deterministisch nicht-deterministisch Vorhersagbarkeit theoretisch ja nein Performance sehr schnell schnell Use Case Spiele, Animation Auslosung, Krypto Quelle xorshift128+ OS-Entropie + Hardware
Side-by-Side-Vergleich der beiden Zufallsquellen mit den fünf wichtigsten Eigenschaften.

Wann reicht Math.random?

Math.random ist für alles, was Spaß machen soll und keine wirtschaftlichen Folgen hat, vollkommen ok. Beispiele:

  • Eine Würfel-App für Brettspiele
  • Eine zufällige Frage-des-Tages-Funktion
  • Mischen der Karten in einem Solitär-Spiel
  • Eine Animation, die zufällige Partikel-Positionen braucht
  • Ein Liebesrechner-Tool, das einen Score würfelt

In all diesen Fällen würde niemand auf die Idee kommen, den Output des Pseudo-Zufalls-Generators zurückzurechnen, um sich einen Vorteil zu verschaffen. Selbst wenn jemand es täte, wäre der Schaden überschaubar.

Wann muss es crypto sein?

Sobald Geld, Wertgegenstände oder ernsthafte Konsequenzen im Spiel sind, gehört crypto.getRandomValues an die Reihe. Konkret:

  • Verlosung mit Preisen, die einen messbaren Wert haben
  • Auslosung von Versuchsteilnehmern in Studien
  • Generierung von Session-Tokens, Passwort-Reset-Codes, API-Keys
  • Verschlüsselungs-Schlüssel für Anwendungs-Daten
  • Initialisierung von kryptographischen Protokollen

Bei allem, was unter Datenschutz oder Sicherheit fällt, ist Math.random eine schlechte Wahl. Hier gibt es keine Diskussion: nimm crypto.

Warum der Namens Picker auf crypto setzt

Der Namens Picker mischt Namen für Auslosungen. Manche Nutzer machen damit eine Instagram-Verlosung mit einem 10-Euro-Gutschein, andere ein Wichteln in der Familie. Wieder andere lassen den Lehrer entscheiden, welcher Schüler die erste Frage in der Klasse beantwortet.

In all diesen Fällen wäre Math.random praktisch ok. Aber: Wir wissen nicht, wer das Tool wofür einsetzt. Vielleicht macht jemand eine Verlosung mit einem 1.000-Euro-Preis und vertraut darauf, dass die Ziehung manipulationssicher ist. Wir möchten ihm diese Sicherheit liefern, auch wenn er nicht explizit danach fragt.

Der technische Aufwand für die Umstellung von Math.random auf crypto.getRandomValues ist minimal. Statt Math.random() schreibst du:

const buf = new Uint32Array(1);
crypto.getRandomValues(buf);
const value = buf[0] / 0x100000000;

Drei Zeilen mehr, gleiche Funktionalität, kryptographisch sicher. Es gibt keinen Grund, das nicht zu tun.

Eine technische Feinheit zum Modulo-Bias

Wenn du aus einer kryptographisch sicheren Zufallszahl einen Index aus einem bestimmten Bereich machst, etwa “ziehe einen der 17 Namen aus dieser Liste”, dann musst du aufpassen. Die naive Variante wäre randomValue % 17. Das funktioniert mathematisch, ist aber nicht perfekt gleichverteilt, wenn 2^32 nicht glatt durch 17 teilbar ist.

Konkret: 2^32 = 4.294.967.296. Geteilt durch 17 ergibt 252.645.135 mit Rest 1. Das heißt, der Wert 0 hat eine winzige Mikroskopische Übergewichtung gegenüber den Werten 1 bis 16. Bei einer Liste von 17 Namen ist die Verzerrung statistisch nicht messbar, aber bei extremen Spielen mit hohen Anforderungen würde man Rejection Sampling nutzen: man wirft den Wert weg, wenn er im “unfair-Bereich” landet, und wirft neu.

Für die Namens-Picker-Praxis ist das egal. Wer aber eine staatliche Lotterie programmiert, sollte sich damit beschäftigen.

Sicherheits-Implikationen in Spielanwendungen

Manche Online-Spiele und kleine Browser-Games setzen Math.random für ihre interne Zufallslogik ein. Das ist meist okay, kann aber zu Problemen werden, wenn das Spiel echte wirtschaftliche Konsequenzen hat. Ein Beispiel: Ein Browser-basiertes Kartenspiel würfelt mit Math.random aus, welche Karten du bekommst. Wenn jemand den internen Zustand des PRNG mitliest (was über lange Beobachtung theoretisch möglich ist), könnte er die nächsten Karten vorhersagen und einen Vorteil haben.

Auch wenn diese Angriffe technisch anspruchsvoll sind und in der Praxis kaum gemacht werden, ist das eine echte Sicherheitslücke. Wer Spiele mit Bezahl-Komponente baut, sollte aus Vorsicht immer crypto.getRandomValues nehmen. Bei kostenlosen Casual-Games ist die Wahrscheinlichkeit einer Ausnutzung praktisch null.

Browser-Support und die Realität

Manchmal hört man das Argument, crypto.getRandomValues sei “neu” und man könne sich nicht darauf verlassen. Das stimmt nicht mehr seit über zehn Jahren. Chrome unterstützt die API seit Version 11 (April 2011), Firefox seit Version 21 (Mai 2013), Safari seit Version 6.1 (Oktober 2013). Microsoft Internet Explorer 11 hat sie unter Bedingungen unterstützt, Edge von Anfang an. Alle modernen mobilen Browser sind ebenfalls dabei. Wer in 2026 ein Web-Tool baut, muss sich um Browser-Support für die Web Crypto API nicht kümmern, das ist seit Jahren Standard.

Wo es kompliziert wird, sind Server-Side-Renderings ohne Browser-Umgebung. In Node.js gibt es ab Version 17 ein globales crypto-Objekt mit denselben Methoden, davor musste man require(‘crypto’) nutzen. Wer ein Tool baut, das sowohl im Browser als auch in Node.js läuft (etwa für Unit-Tests), sollte das berücksichtigen. Im Namens Picker ist das geregelt: im Browser läuft crypto.getRandomValues, in den Vitest-Tests gibt es einen Fallback auf das Node-globale crypto-Objekt.

Testen: Wie verifiziere ich die Verteilung?

Wer einer Zufallsquelle nicht traut, kann sie testen. Ein einfacher Test: erzeuge 1.000.000 Zahlen, teile sie in 100 Buckets (jeweils 1 Prozent des Zielbereichs) und zähle, wie viele Zahlen pro Bucket landen. Bei perfekter Gleichverteilung sollten in jedem Bucket etwa 10.000 Zahlen sein, mit einer kleinen Schwankung von ein paar Prozent.

Bei Math.random und crypto.getRandomValues siehst du, dass beide gut gleichverteilt sind. Die Unterschiede liegen unter der Messgenauigkeit. Wo es interessant wird, sind Stress-Tests mit Korrelationsmustern: zeichne aufeinanderfolgende Werte auf einer x-y-Ebene, schau, ob sich Muster bilden. Bei einem schlechten Pseudo-Zufalls-Generator (etwa dem alten RANDU aus den 1960ern) sieht man klare Streifen. Bei xorshift128+ und bei crypto.getRandomValues sieht es aus wie pure Streuung.

Für eine Auslosungs-Software ist dieser Test nice to have, aber nicht notwendig. Die Standard-Implementierungen in modernen Browsern sind ausreichend geprüft.

Was hängenbleibt

Math.random und crypto.getRandomValues sind beide schnell, beide statistisch gleichverteilt, beide in allen modernen Browsern verfügbar. Der Unterschied liegt in der Vorhersagbarkeit. Math.random nutzt einen Pseudo-Zufalls-Generator, der theoretisch berechenbar ist. crypto.getRandomValues zapft die Entropie des Betriebssystems an, die aus physikalischen Quellen kommt und nicht vorhersagbar ist. Für Spaß-Anwendungen reicht Math.random. Für alles mit echten Konsequenzen ist crypto.getRandomValues die richtige Wahl, und weil der Mehraufwand null ist, gibt es keinen guten Grund, nicht von Anfang an darauf zu setzen. Im Namens Picker laufen beide Wege im Browser, der Picker selbst nutzt aus Vorsicht crypto.getRandomValues, damit auch ein Vereinsvorsitzender mit einer 1.000-Euro-Verlosung guten Gewissens darauf vertrauen kann.

FAQ

Häufige Fragen

Ist Math.random unsicher?

Unsicher ist das falsche Wort. Math.random ist statistisch gleichverteilt und für Spaß-Anwendungen, Spiele, Animationen und Mini-Auslosungen vollkommen passend. Was Math.random nicht ist: kryptographisch sicher. Das heißt, jemand mit genug Beobachtung des Outputs könnte theoretisch den internen Zustand des Pseudo-Zufalls-Generators rekonstruieren und die nächste Zahl vorhersagen. Praktisch ist das aufwendig, aber bei einer Verlosung mit echten Preisen ist die Frage nicht, ob es schwer ist, sondern ob du dich darauf einlassen willst. Bei kryptographisch sicheren Quellen stellt sich die Frage nicht.

Was ist xorshift128+ und warum nutzt V8 das?

xorshift128+ ist ein Algorithmus für Pseudo-Zufalls-Generatoren, der seit 2015 in der V8-Engine (also Chrome und Node.js) als Backend für Math.random läuft. Davor wurde MWC1616 verwendet, das in Tests Verzerrungen zeigte. xorshift128+ ist schnell, hat einen internen Zustand von 128 Bit und eine Periode von 2^128 minus 1, was bedeutet: nach so vielen Aufrufen wiederholt sich die Sequenz. Das ist mehr Zahlen als ein Mensch jemals in einem Browser-Tab abrufen wird. Für Spielzwecke ist das absolut ausreichend, kryptographisch sicher ist es trotzdem nicht.

Wie funktioniert die Web Crypto API technisch?

crypto.getRandomValues füllt einen TypedArray mit kryptographisch sicheren Zufallswerten. Im Hintergrund ruft der Browser den Zufallsgenerator des Betriebssystems auf. Auf Linux ist das getrandom() oder /dev/urandom, auf Windows BCryptGenRandom, auf macOS getentropy. Diese Generatoren sammeln Entropie aus verschiedenen physikalischen Quellen, etwa Mausbewegungen, Tastatur-Timings, Netzwerk-Interrupts und auf modernen CPUs auch aus dem dedizierten Zufalls-Befehlssatz RDRAND oder RDSEED von Intel. Das Ergebnis ist nicht vorhersagbar, auch nicht mit Aufzeichnung früherer Werte.

Warum nutzt der Namens Picker crypto und nicht Math.random?

Aus Vorsicht und Konsistenz. Der Mehraufwand für crypto.getRandomValues ist null, die Performance praktisch identisch, und wenn jemand das Tool für eine Verlosung mit Wertgegenständen nutzt, hat er die gleiche Sicherheit wie bei einer professionellen Ziehungs-Software. Wir hätten Math.random nehmen können, hätten dann aber bei jeder Frage erklären müssen, warum nicht crypto. Andersrum ist die Antwort einfach: wir sind auf der sicheren Seite, es kostet nichts extra. Außerdem ist crypto.getRandomValues in allen modernen Browsern verfügbar (seit Chrome 11, Firefox 21, Safari 6), Browser-Support ist also kein Argument mehr.

Gibt es einen Performance-Unterschied zwischen den beiden?

Praktisch nein, theoretisch ein bisschen. Math.random ist ein direkter Funktionsaufruf, der einen einzigen 64-Bit-Wert produziert. crypto.getRandomValues braucht einen TypedArray als Buffer und füllt den mit Werten, was ein paar Mikrosekunden Overhead bedeutet. Bei einer Ziehung von 1.000 Namen reden wir von einem Unterschied von vielleicht einer Millisekunde insgesamt. Im Namens Picker, der typischerweise zwischen 5 und 100 Namen verarbeitet, ist der Unterschied unmessbar. Wer Zufallswerte in einer engen Animationsschleife mit 60 fps generieren muss, sollte Math.random nehmen. Sonst ist crypto.getRandomValues die saubere Default-Wahl.

Anzeige

Quellen

Worauf dieser Ratgeber sich stützt

Verwandte Ratgeber

Weiterlesen

Veröffentlicht · zuletzt geprüft
Verantwortlich: Mateusz Viola
Anzeige
Anzeige
Anzeige
Anzeige