Sichere Authentifizierung in Go: Code ohne Schwachstellen schreiben

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum Authentifizierung in Go kein Kinderspiel ist?

\n\n

Go ist eine Sprache, die für Geschwindigkeit und Zuverlässigkeit gewählt wird. Aber selbst der schnellste Server wird zur Rübe, wenn darüber Passwörter gestohlen werden können. Sichere Authentifizierung in Go-Anwendungen ist nicht einfach "Bibliothek installiert und vergessen". Es ist eine Wissenschaft: Wie speichert man Passwörter, wie vermasselt man JWT nicht, wie schützt man sich vor CSRF, wenn alles bereits brennt.

\n\n

In diesem Artikel halten wir keine Vorlesungen über Theorie. Wir schreiben Code. Echten, funktionsfähigen Code, den Sie sofort in Ihr Projekt einfügen können. Wir behandeln die drei Säulen der Sicherheit: Passwort-Hashing (bcrypt), Arbeit mit JWT-Tokens und Schutz vor Cross-Site Request Forgery (CSRF).

\n\n

Passwörter richtig hashen: Warum md5 böse ist

\n\n

Der erste Schritt zur Sicherheit ist, niemals, hören Sie, niemals Passwörter im Klartext zu speichern. Selbst wenn Sie Ihrer Datenbank vertrauen. Ein Einbruch kann jedem passieren (fragen Sie Yahoo oder Adobe). Richtiges Hashing ist Ihr Schutzschild.

\n\n

In Go ist die Standardwahl golang.org/x/crypto/bcrypt. Warum gerade bcrypt? Es ist resistent gegen Brute-Force-Angriffe (enthält "Salt" und verlangsamt Berechnungen). MD5 oder SHA-1 werden in Mikrosekunden berechnet. Bcrypt benötigt Hunderte von Millisekunden. Für einen Angreifer ist das eine Katastrophe, für den Benutzer unsichtbar.

\n\n

Beispiel: Benutzerregistrierung

\n\n
package main\n\nimport (\n    "fmt"\n    "golang.org/x/crypto/bcrypt"\n)\n\nfunc hashPassword(password string) (string, error) {\n    bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)\n    return string(bytes), err\n}\n\nfunc checkPasswordHash(password, hash string) bool {\n    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))\n    return err == nil\n}\n\nfunc main() {\n    password := "mySecretPass123"\n    hash, _ := hashPassword(password)\n\n    fmt.Println("Passwort:", password)\n    fmt.Println("Hash:  ", hash)\n\n    match := checkPasswordHash(password, hash)\n    fmt.Println("Stimmt überein:", match)\n}
\n\n

Beachten Sie: bcrypt.DefaultCost sind 10 Iterationen. Für die Produktion können Sie auf 12-14 erhöhen, aber übertreiben Sie es nicht, sonst bricht der Server unter der Last zusammen. Testen Sie auf Ihrer eigenen Hardware.

\n\n

Passwortprüfung beim Login

\n\n

Ganz einfach: Passwort aus dem Formular nehmen, Hash aus der Datenbank holen, mit bcrypt.CompareHashAndPassword vergleichen. Wenn nil zurückgegeben wird, ist der Benutzer legitim. Bei Fehler senden wir 401.

\n\n
func loginHandler(w http.ResponseWriter, r *http.Request) {\n    // Passwort aus dem Formular holen\n    storedHash := getUserHashFromDB(r.FormValue("email"))\n    if !checkPasswordHash(r.FormValue("password"), storedHash) {\n        http.Error(w, "Falsches Passwort", http.StatusUnauthorized)\n        return\n    }\n    // Session oder Token erstellen\n}
\n\n

JWT: Leichte Authentifizierung mit Tücken

\n\n

Nachdem der Benutzer sein Passwort eingegeben hat, muss ihm ein "Ausweis" ausgestellt werden. Eine beliebte Methode ist JWT (JSON Web Token). Dies ist ein kompaktes Token, das Benutzerdaten und eine Signatur enthält. Aber der Teufel steckt im Detail: Eine falsche JWT-Implementierung kann Ihre Anwendung angreifbar machen.

\n\n

Korrekte JWT-Generierung in Go

\n\n

Wir verwenden die Bibliothek github.com/golang-jwt/jwt/v5. Schreiben Sie niemals Ihr eigenes Rad für Kryptographie – nur geprüfte Bibliotheken.

\n\n
import (\n    "time"\n    "github.com/golang-jwt/jwt/v5"\n)\n\nvar jwtKey = []byte("my_secret_key_which_must_be_long_and_random")\n\ntype Claims struct {\n    Username string `json:"username"`\n    jwt.RegisteredClaims\n}\n\nfunc generateToken(username string) (string, error) {\n    expirationTime := time.Now().Add(15 * time.Minute)\n    claims := &Claims{\n        Username: username,\n        RegisteredClaims: jwt.RegisteredClaims{\n            ExpiresAt: jwt.NewNumericDate(expirationTime),\n        },\n    }\n\n    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)\n    return token.SignedS                

Blogs

Buchempfehlungen