Hinzufügen eines zweiten Faktors zu einem Login-Skript

CybersicherheitBeginner
Jetzt üben

Einführung

Die Multi-Faktor-Authentifizierung (MFA) reduziert das Risiko einer Kontokompromittierung, indem sie mehr als eine Art von Nachweis erfordert. Ein Passwort ist etwas, das der Benutzer weiß. Ein zweiter Faktor kann ein Code von einem separaten Gerät, einer App, einer Datei oder einem Hardware-Token sein.

In diesem Lab beginnen Sie mit einem Python-Login-Skript, das nur ein Passwort verwendet, und fügen dann einen einfachen zweiten Faktor hinzu. Um das Lab einsteigerfreundlich und deterministisch zu halten, ist der zweite Faktor ein HMAC-basierter Code, der aus einer geschützten Geheimdatei generiert wird.

Testen des reinen Passwort-Logins

In diesem Schritt führen Sie das ursprüngliche Login-Skript aus. Es prüft lediglich einen Benutzernamen und ein Passwort. Dies ist eine Ein-Faktor-Authentifizierung, da der einzige Nachweis etwas ist, das der Benutzer weiß.

Wechseln Sie in das Projektverzeichnis:

cd /home/labex/project

Untersuchen Sie die vorbereiteten Dateien:

ls -l

Betrachten Sie die Benutzerdatenbank:

cat users.json

Führen Sie einen erfolgreichen Login nur mit Passwort durch:

python3 login.py alice wonderland

Die Ausgabe sollte wie folgt lauten:

login ok

Versuchen Sie nun ein falsches Passwort:

python3 login.py alice wrong

Dieser Befehl sollte login failed ausgeben. Ein fehlgeschlagener Login wird mit einem Status ungleich Null beendet, was für diesen Test normal ist.

Führen Sie den Checker für den Ausgangszustand aus:

python3 mfa-check.py password-only

Das erwartete Ergebnis ist:

password-only: complete

Erstellen des Geheimnisses für den zweiten Faktor

In diesem Schritt erstellen Sie ein separates Geheimnis für den zweiten Faktor. In einem echten MFA-System könnte dieses Geheimnis in einer Authenticator-App oder auf einem Hardware-Token gespeichert sein. In diesem Lab handelt es sich um eine lokale Datei, damit das Verhalten leicht zu überprüfen und nachzuvollziehen ist.

Erstellen Sie einen geheimen Wert:

printf 'labex-mfa-secret-2026\n' > mfa_secret.txt

Beschränken Sie die Zugriffsrechte der Datei so, dass nur der Besitzer sie lesen und schreiben kann:

chmod 600 mfa_secret.txt

Überprüfen Sie die Berechtigungen:

ls -l mfa_secret.txt

Die Berechtigungsbits sollten mit -rw------- beginnen:

-rw------- ... mfa_secret.txt

Führen Sie den Checker für das Geheimnis aus:

python3 mfa-check.py secret

Das erwartete Ergebnis ist:

secret: complete

Generieren eines Login-Codes

In diesem Schritt erstellen Sie einen kleinen Codegenerator. Er verwendet HMAC-SHA256, um die Geheimdatei mit dem Benutzernamen zu kombinieren. HMAC ist hier nützlich, da dieselbe Eingabe und dasselbe Geheimnis denselben kurzen Code erzeugen, während jemand ohne das Geheimnis den Code nicht einfach erstellen kann.

Erstellen Sie generate-code.py:

cat > generate-code.py <<'PY'
#!/usr/bin/env python3
import hmac
import hashlib
import sys
from pathlib import Path

if len(sys.argv) != 2:
    print("usage: generate-code.py USERNAME")
    raise SystemExit(2)

username = sys.argv[1]
secret = Path("mfa_secret.txt").read_text().strip().encode()
digest = hmac.new(secret, username.encode(), hashlib.sha256).hexdigest()
print(digest[:6])
PY

Machen Sie das Skript ausführbar:

chmod +x generate-code.py

Generieren Sie einen Code für alice:

python3 generate-code.py alice

Sie sollten diesen deterministischen sechsstelligen Code sehen:

21f18f

Führen Sie den Checker für den Generator aus:

python3 mfa-check.py generator

Das erwartete Ergebnis ist:

generator: complete

Erzwingen des zweiten Faktors

In diesem Schritt ersetzen Sie das Login-Skript, sodass sowohl das Passwort als auch der generierte Code erforderlich sind. Dies ist die entscheidende Änderung für MFA: Das Passwort allein reicht nicht mehr aus.

Ersetzen Sie login.py durch diese MFA-fähige Version:

cat > login.py <<'PY'
#!/usr/bin/env python3
import hmac
import hashlib
import json
import sys
from pathlib import Path

USERS = Path("users.json")
SECRET = Path("mfa_secret.txt")

def expected_code(username):
    secret = SECRET.read_text().strip().encode()
    digest = hmac.new(secret, username.encode(), hashlib.sha256).hexdigest()
    return digest[:6]

def main():
    if len(sys.argv) != 4:
        print("usage: login.py USERNAME PASSWORD MFA_CODE")
        return 2

    username, password, code = sys.argv[1], sys.argv[2], sys.argv[3]
    users = json.loads(USERS.read_text())
    if users.get(username, {}).get("password") != password:
        print("login failed")
        return 1

    if not hmac.compare_digest(code, expected_code(username)):
        print("mfa failed")
        return 1

    print("login ok")
    return 0

if __name__ == "__main__":
    raise SystemExit(main())
PY

Stellen Sie sicher, dass das Skript ausführbar ist:

chmod +x login.py

Generieren Sie einen neuen Code und speichern Sie ihn in einer Shell-Variablen:

CODE="$(python3 generate-code.py alice)"

Verwenden Sie das korrekte Passwort und den Code zusammen:

python3 login.py alice wonderland "$CODE"

Die Ausgabe sollte wie folgt lauten:

login ok

Führen Sie den Checker für die MFA-Erzwingung aus:

python3 mfa-check.py enforced

Das erwartete Ergebnis ist:

enforced: complete

Testen von MFA-Fehlern und -Erfolgen

In diesem Schritt testen Sie das endgültige Login-Verhalten. Ein korrektes Passwort ohne den zweiten Faktor sollte fehlschlagen, ein falscher Code sollte fehlschlagen, und das korrekte Passwort plus der korrekte Code sollten erfolgreich sein.

Versuchen Sie zuerst den alten Befehl nur mit Passwort:

python3 login.py alice wonderland || true

Die Ausgabe sollte die neue Nutzungsmeldung anzeigen, da der MFA-Code fehlt:

usage: login.py USERNAME PASSWORD MFA_CODE

Versuchen Sie einen falschen Code:

python3 login.py alice wonderland 000000 || true

Die Ausgabe sollte wie folgt lauten:

mfa failed

Generieren Sie den korrekten Code und melden Sie sich an:

CODE="$(python3 generate-code.py alice)"
python3 login.py alice wonderland "$CODE"

Die Ausgabe sollte wie folgt lauten:

login ok

Führen Sie den vollständigen Checker aus:

python3 mfa-check.py all

Die endgültige Ausgabe sollte zeigen, dass alle MFA-Komponenten vollständig sind:

secret: complete
generator: complete
enforced: complete

Zusammenfassung

Sie haben ein Login-Skript, das nur ein Passwort erforderte, in einen einfachen Multi-Faktor-Login-Ablauf umgewandelt. Sie haben ein separates MFA-Geheimnis erstellt, einen HMAC-basierten Code generiert, diesen Code im Login-Skript zur Pflicht gemacht und sowohl Fehler- als auch Erfolgsfälle getestet.

Der grundlegende Sicherheitsgedanke dabei ist, dass ein gestohlenes Passwort allein nicht ausreichen sollte, wenn ein unabhängiger zweiter Nachweis erforderlich ist.