10 Wege, Passwoerter in Python zu generieren (nur Standardbibliothek)

Ob API-Token, temporaere Passwoerter oder Einmal-Codes – in der Praxis braucht man haeufig zufaellige Zeichenketten. Python bringt alles mit, was du dafuer brauchst: kein pip install noetig. Dieser Artikel zeigt dir zehn Muster, von einfach bis fortgeschritten.

Hinweis: Fuer sicherheitsrelevante Anwendungen solltest du immer das secrets-Modul verwenden. random ist nicht kryptografisch sicher.

1. secrets.token_urlsafe – Der Allrounder

Die einfachste und sicherste Methode fuer Tokens. Das Ergebnis ist Base64-URL-kodiert und eignet sich perfekt fuer URLs und APIs:

urlsafe_token.py
import secrets

token = secrets.token_urlsafe(32)
print(token)  # z.B. 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1c...'

Der Parameter gibt die Anzahl der Bytes an. 32 Bytes ergeben etwa 43 Zeichen nach der Base64-Kodierung. Fuer die meisten Zwecke ist das mehr als ausreichend.

2. secrets.token_hex – Hexadezimale Tokens

Wenn du nur Hex-Zeichen brauchst (0-9, a-f), ist token_hex die richtige Wahl:

hex_token.py
import secrets

hex_token = secrets.token_hex(16)
print(hex_token)  # z.B. 'a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5'
print(len(hex_token))  # 32 Zeichen (2 Hex-Zeichen pro Byte)

3. secrets.choice – Passwort aus Zeichenpool

Fuer klassische Passwoerter mit bestimmten Zeichenklassen kombinierst du secrets.choice mit string-Konstanten:

choice_password.py
import secrets
import string

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

print(generate_password())      # z.B. 'k#9Lm!xQ2@pW7&rT'
print(generate_password(24))     # 24 Zeichen

Mit string.ascii_letters erhaeltst du Gross- und Kleinbuchstaben, string.digits liefert Ziffern und string.punctuation die Sonderzeichen.

4. Passwort mit Mindestanforderungen

Viele Systeme verlangen mindestens einen Grossbuchstaben, eine Ziffer und ein Sonderzeichen. So stellst du das sicher:

strong_password.py
import secrets
import string

def strong_password(length=16):
    if length < 4:
        raise ValueError("Mindestlaenge ist 4")
    alphabet = string.ascii_letters + string.digits + string.punctuation
    while True:
        pw = "".join(secrets.choice(alphabet) for _ in range(length))
        if (any(c.islower() for c in pw)
                and any(c.isupper() for c in pw)
                and any(c.isdigit() for c in pw)
                and any(c in string.punctuation for c in pw)):
            return pw

print(strong_password())

Die while True-Schleife generiert so lange neue Passwoerter, bis alle Anforderungen erfuellt sind. Bei 16 Zeichen klappt das fast immer im ersten Versuch.

5. Passphrase im Diceware-Stil

Passphrases sind laenger, aber leichter zu merken. Hier ein Beispiel mit einer eigenen Wortliste:

passphrase.py
import secrets

WOERTER = [
    "apfel", "birne", "kirsche", "dattel", "feige",
    "traube", "kiwi", "mango", "orange", "pflaume",
    "wolke", "berg", "fluss", "stein", "blatt",
    "stern", "mond", "sonne", "regen", "wind",
]

def passphrase(wort_anzahl=4, trennzeichen="-"):
    return trennzeichen.join(
        secrets.choice(WOERTER) for _ in range(wort_anzahl)
    )

print(passphrase())       # z.B. 'berg-mango-stern-regen'
print(passphrase(6, "."))  # z.B. 'kiwi.blatt.sonne.wind.birne.stein'

In der Praxis wuerdest du eine groessere Wortliste verwenden (z.B. die EFF-Wortliste mit 7776 Eintraegen). Je groesser die Liste, desto mehr Entropie pro Wort.

6. os.urandom – Rohe Zufallsbytes

Wenn du rohe Bytes brauchst (z.B. fuer Verschluesselung), ist os.urandom die niedrigste Ebene:

urandom_bytes.py
import os
import base64

raw = os.urandom(32)
print(raw.hex())                    # Hex-Darstellung
print(base64.b64encode(raw).decode())  # Base64-Darstellung

# Nur ASCII-Buchstaben und Ziffern
token = base64.b32encode(os.urandom(20)).decode().rstrip("=")
print(token)  # z.B. 'JBSWY3DPEHPK3PXP4GQRGZMB3FQWI'

os.urandom liest direkt vom Betriebssystem-Zufallsgenerator (/dev/urandom auf Linux). Das secrets-Modul nutzt intern dieselbe Quelle.

7. uuid.uuid4 – Einmalige Bezeichner

UUIDs sind keine Passwoerter im klassischen Sinn, aber hervorragend als eindeutige Bezeichner geeignet:

uuid_token.py
import uuid

u = uuid.uuid4()
print(u)        # z.B. 'a3f2b8c1-d4e5-4f6a-b8c9-d0e1f2a3b4c5'
print(u.hex)    # ohne Bindestriche: 'a3f2b8c1d4e54f6ab8c9d0e1f2a3b4c5'

# Als kurzer Token
short = u.hex[:12]
print(short)    # z.B. 'a3f2b8c1d4e5'

UUID4 basiert auf Zufallszahlen und bietet 122 Bit Entropie. Die Wahrscheinlichkeit einer Kollision ist astronomisch gering.

8. hashlib – Deterministische Tokens

Manchmal brauchst du einen Token, der sich aus einer Eingabe reproduzierbar ableiten laesst:

hashlib_token.py
import hashlib
import time

def make_token(user_id, secret_key):
    ts = str(int(time.time()))
    raw = f"{user_id}:{ts}:{secret_key}"
    return hashlib.sha256(raw.encode()).hexdigest()[:32], ts

token, timestamp = make_token("user42", "mein-geheimer-schluessel")
print(f"Token: {token}")
print(f"Erstellt: {timestamp}")

Achtung: Solche Tokens sind nur so sicher wie der secret_key. Fuer echte HMAC-basierte Tokens verwende das hmac-Modul.

9. hmac – Signierte Tokens

Mit HMAC kannst du Tokens erstellen, deren Echtheit du spaeter verifizieren kannst:

hmac_token.py
import hmac
import hashlib
import time

SECRET = b"super-geheimer-schluessel"

def create_signed_token(data):
    ts = str(int(time.time()))
    msg = f"{data}:{ts}".encode()
    sig = hmac.new(SECRET, msg, hashlib.sha256).hexdigest()
    return f"{data}:{ts}:{sig}"

def verify_token(token):
    parts = token.rsplit(":", 2)
    if len(parts) != 3:
        return False
    data, ts, sig = parts
    msg = f"{data}:{ts}".encode()
    expected = hmac.new(SECRET, msg, hashlib.sha256).hexdigest()
    return hmac.compare_digest(sig, expected)

token = create_signed_token("user42")
print(token)
print(verify_token(token))  # True

hmac.compare_digest verhindert Timing-Angriffe beim Vergleich. Verwende diese Funktion immer statt dem normalen ==-Operator.

10. random – Nur fuer nicht-sicherheitsrelevante Zwecke

Warnung: Das random-Modul verwendet den Mersenne-Twister-Algorithmus, der vorhersagbar ist. Verwende es niemals fuer Passwoerter, Tokens oder Sicherheitsfunktionen.

random_unsicher.py
import random
import string

# NUR fuer Tests, Demos oder Spiele!
def demo_password(length=12):
    chars = string.ascii_letters + string.digits
    return "".join(random.choices(chars, k=length))

print(demo_password())

# Reproduzierbar mit Seed (nützlich fuer Tests)
random.seed(42)
print(demo_password())  # immer dasselbe Ergebnis

Der einzige legitime Einsatz: Test-Fixtures, wo du reproduzierbare Zufallsdaten brauchst. In Produktion immer secrets nehmen.

Zusammenfassung

Hier ein schneller Ueberblick, welche Methode wofuer geeignet ist:

Sicher (kryptografisch): secrets.token_urlsafe, secrets.token_hex, secrets.choice, os.urandom, hmac

Eindeutig (aber kein Passwort): uuid.uuid4, hashlib

Unsicher (nur Tests): random

Fuer die allermeisten Faelle ist secrets.token_urlsafe(32) die beste Wahl. Einfach, sicher und sofort einsatzbereit.

Comments

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert