Warum Authentifizierung in Go kein Kinderspiel ist?
\n\nGo 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\nIn 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\nPasswörter richtig hashen: Warum md5 böse ist
\n\nDer 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\nIn 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.
Beispiel: Benutzerregistrierung
\n\npackage 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\nBeachten 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.
Passwortprüfung beim Login
\n\nGanz 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.
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\nJWT: Leichte Authentifizierung mit Tücken
\n\nNachdem 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\nKorrekte JWT-Generierung in Go
\n\nWir verwenden die Bibliothek github.com/golang-jwt/jwt/v5. Schreiben Sie niemals Ihr eigenes Rad für Kryptographie – nur geprüfte Bibliotheken.
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