Zurück zur Startseite

Python Passwortgenerierung: secrets statt random

Der Artikel erklärt, warum das random-Modul für die Passwortgenerierung ungeeignet ist aufgrund Mersenne Twister-Determinismus. Vergleich mit secrets, Entropie-Analyse und fehlgeschlagener Seed-Angriffversuch. Empfehlungen für sicheren Code.

Warum random für Passwörter in Python gefährlich ist: secrets in action
Advertisement 728x90

Kryptografisch sichere Passwortgenerierung in Python: random vs secrets

Entropie definiert die Qualität eines Passworts nicht als Eigenschaft der Zeichenkette selbst, sondern als Merkmal des Generierungsprozesses. Die Formel H = L × log₂(N) geht von einer unabhängigen und gleichwahrscheinlichen Auswahl jedes Zeichens aus einem Alphabet der Größe N über eine Länge L aus. Für 8 Kleinbuchstaben (N=26): ~37,6 Bits. Für vollständiges ASCII (N=94): ~79 Bits.

Ein häufiges Missverständnis: Die scheinbare Zufälligkeit eines Passworts garantiert nicht seine Stärke. Zwei Passwörter wie f9A$kL2pQzX1 können dieselbe formale Entropie haben, aber je nach verwendetem Generator sehr unterschiedliche reale Sicherheit bieten.

Das random-Modul: ein deterministischer PRNG

Das random-Modul implementiert den Mersenne Twister (MT19937) mit einem internen Zustand von ~19937 Bits. Jeder Wert ist deterministisch basierend auf dem vorherigen. Der Standard-Seed wird von os.urandom() bezogen, aber die inhärenten Eigenschaften des PRNG bleiben:

Google AdInline article slot
  • Determinismus: Ein Seed ergibt eine vorhersehbare Sequenz.
  • Wiederherstellbarkeit: Der Zustand kann aus ~624 rohen 32-Bit-Ausgaben rekonstruiert werden.
  • Fehlende kryptografische Sicherheit: Nicht resistent gegen Zustandsrückgewinnungsangriffe.

Beispiel für typischen Code:

import random
import string

alphabet = string.ascii_letters + string.digits
def generate_password(length=12):
    return ''.join(random.choice(alphabet) for _ in range(length))

Das Passwort ist ein Ausschnitt der PRNG-Sequenz. Wenn der Zustand bekannt ist, ist die Sequenz vorhersehbar.

Das secrets-Modul: direkter Zugriff auf Systementropie

Secrets verwendet os.urandom() direkt für jeden Aufruf:

Google AdInline article slot
  • secrets.randbelow(n) → os.urandom().
  • random.SystemRandom() → os.urandom().

Es gibt keinen festen Zustand, keinen Determinismus. Jedes Byte stammt aus Hardwarequellen: Interrupts, Netzwerkrauschen, Mausbewegungen.

Der Unterschied ist entscheidend: random erzeugt eine Illusion von Sicherheit, secrets bietet sie.

Praktischer Angriff: Wiederherstellung von Seed und Zustand

Experiment mit 5 aufeinanderfolgenden Passwörtern von GigaChat (Länge 12, Python 3.9.18, Zeit 24.03.2026 11:11):

Google AdInline article slot

Hypothese: Seed = Server-Zeitstempel ±1 Stunde.

from datetime import datetime, timedelta

base_time = datetime(2026, 3, 24, 11, 11, 0)
window_seconds = 3600
for offset in range(-window_seconds, window_seconds):
    t = base_time + timedelta(seconds=offset)
    seed = int(t.timestamp())
    # Initialisiere random.seed(seed) und überprüfe

Ergebnis: keine Übereinstimmungen. Die Verwendung von os.urandom() für den Seed vereitelt brute-force zeitbasierte Angriffe.

Ein echter Angriff auf MT19937 erfordert 624 rohe Werte. Passwörter sind eine verzerrte Ausgabe (Auswahl → Zeichen), insgesamt nur 60 Auswahlen für 5 Passwörter. Eine Wiederherstellung ist unmöglich.

Angriffsgrenzen:

  • Erfordert rohe PRNG-Ausgaben.
  • Vorhersehbarer Seed (Zeit, PID).
  • Wiederholte Verwendung desselben Generators.
  • Bekannter Algorithmus.

Wichtige Erkenntnisse

  • Entropie ist eine Eigenschaft des Prozesses, nicht des Ergebnisses: Überprüfen Sie immer Ihren Generator.
  • random (Mersenne Twister) ist anfällig für Zustandsrückgewinnung bei ausreichenden Daten.
  • secrets/os.urandom ist die einzige Wahl für Passwörter, Schlüssel und Tokens.
  • Die Illusion von Zufälligkeit durch random ist in der Produktion gefährlich.
  • PRNG-Angriffe sind nur mit Seed-Fehlern oder Zustandslecks realistisch.

Empfehlungen für mittlere/senior Entwickler

Implementieren Sie in Ihrem Code:

import secrets
import string

alphabet = string.ascii_letters + string.digits + string.punctuation
def secure_password(length=16):
    return ''.join(secrets.choice(alphabet) for _ in range(length))

Vermeiden Sie:

  • Die Verwendung von random für Authentifizierung.
  • Feste Seeds.
  • Wiederverwendung von Generatoren.

Test: Generieren Sie 10⁶ Passwörter, prüfen Sie auf gleichmäßige Verteilung (chi²).

— Editorial Team

Advertisement 728x90

Weiterlesen