slogan3

Ontwerp en implementeer veilige authenticatie in Go-webtoepassingen

description

Met deze prompt kun je een robuust en veilig authenticatiesysteem opzetten in je Go-webapplicatie, waardoor je gebruikersgegevens beschermd zijn en je applicatie voldoet aan moderne beveiligingsstandaarden. Het voorkomt veelvoorkomende beveiligingsfouten en maakt gebruik van actuele technologieën zoals JWT en veilige wachtwoordhashing.

prompt

Help me bij het ontwerpen en implementeren van een veilige authenticatiesysteem voor mijn Go-webapplicatie. Leg uit hoe ik gebruikersauthenticatie kan opzetten met behulp van JW ...

try_prompt

generate_helper
disclaimerOnPageApi

ai_answers

provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een overzicht en stapsgewijze aanpak voor het ontwerpen en implementeren van een veilig authenticatiesysteem in je Go-webapplicatie met gebruik van net/http, JWT, sessiebeheer, wachtwoordhashing en beveiligingsmaatregelen: 1. **Gebruikersregistratie en wachtwoordhashing** - Gebruik bcrypt voor het hashen van wachtwoorden: ```go import "golang.org/x/crypto/bcrypt" func HashPassword(password string) (string, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) return string(bytes), err } func CheckPasswordHash(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } ``` - Tijdens registratie, has je het wachtwoord en sla je de hash op in de database. 2. **JWT-generatie en -verificatie** - Gebruik bijvoorbeeld de `github.com/dgrijalva/jwt-go` of `github.com/golang-jwt/jwt` bibliotheek. - Genereren van een token na succesvolle login: ```go import "github.com/golang-jwt/jwt" var jwtKey = []byte("je_veilige_zeer_geheime_sleutel") func GenerateJWT(userID string) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "user_id": userID, "exp": time.Now().Add(15 * time.Minute).Unix(), // vervalt na 15 min }) tokenString, err := token.SignedString(jwtKey) return tokenString, err } ``` - Verificatie bij elke protected route: ```go func ValidateJWT(tokenString string) (*jwt.Token, error) { return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("invalid signing method") } return jwtKey, nil }) } ``` 3. **Authenticatie proces** - Bij login: - Controleer wachtwoord met `CheckPasswordHash`. - Genereer JWT en stuur terug naar de client (meestal in een HTTP-only cookie of in de response body). - Bij protected routes: - Lees de JWT uit de Authorization header of cookie. - Valideer de token. - Indien geldig, geef toegang. 4. **Sessiebeheer** - Hoewel JWT stateless is, kun je sessie-informatie combineren door server-side sessiebeheer (bijvoorbeeld met Redis). - Alternatief: Gebruik HTTP-only cookies met JWT, zodat tokens automatisch worden meegestuurd. - Voor extra veiligheid, kun je tokens opslaan in een blacklist bij uitloggen of bij verdachte activiteiten. 5. **Beveiligingsmaatregelen** - **Wachtwoordhashing:** Zoals hierboven met bcrypt. - **Tokenvernieuwing (Refresh tokens):** - Gebruik aparte refresh tokens met langere geldigheid. - Bij verval van access token, gebruik refresh token om nieuwe JWT te genereren. - Store refresh tokens veilig (bijvoorbeeld in database, met beperkte levensduur). - **Secure cookies:** - Plaats tokens in HTTP-only, Secure, SameSite cookies om CSRF en XSS te voorkomen. - **Validatie en logging:** - Log mislukte pogingen. - Beperk brute-force aanvallen met rate limiting. 6. **Voorbeeld van eenvoudige login en protected route** ```go func loginHandler(w http.ResponseWriter, r *http.Request) { // Ontvang gebruikersnaam en wachtwoord uit request // Controleer wachtwoord // Genereer JWT tokenString, err := GenerateJWT(userID) if err != nil { http.Error(w, "Fout bij tokengeneratie", http.StatusInternalServerError) return } // Zet token in HTTP-only cookie http.SetCookie(w, &http.Cookie{ Name: "auth_token", Value: tokenString, HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, Expires: time.Now().Add(15 * time.Minute), }) w.Write([]byte("Inloggen gelukt")) } func protectedHandler(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("auth_token") if err != nil { http.Error(w, "Niet ingelogd", http.StatusUnauthorized) return } token, err := ValidateJWT(cookie.Value) if err != nil || !token.Valid { http.Error(w, "Ongeldige token", http.StatusUnauthorized) return } // Toegang verleend w.Write([]byte("Welkom bij de beveiligde route")) } ``` **Samenvatting:** - Gebruik bcrypt voor wachtwoordhashing. - Implementeer JWT voor stateless authenticatie. - Plaats JWT in HTTP-only cookies voor extra veiligheid. - Implementeer refresh tokens voor tokenvernieuwing. - Voeg beveiligingsheaders en rate limiting toe. - Log alle beveiligingsgerelateerde gebeurtenissen. Wil je een uitgewerkt voorbeeld of hulp bij specifieke onderdelen?
provider: deepseek
model: deepseek-chat
Ik help je graag met het ontwerpen van een veilig authenticatiesysteem in Go met net/http. Hier is een complete uitleg: ## 1. Wachtwoordhashing (bcrypt) ```go import "golang.org/x/crypto/bcrypt" func HashPassword(password string) (string, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) return string(bytes), err } func CheckPasswordHash(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } ``` ## 2. JWT Implementatie ```go import ( "github.com/golang-jwt/jwt/v4" "time" ) var jwtKey = []byte("jouw_veilige_secret_sleutel") // Gebruik environment variable! type Claims struct { UserID string `json:"user_id"` Email string `json:"email"` jwt.RegisteredClaims } func GenerateJWT(userID, email string) (string, error) { expirationTime := time.Now().Add(24 * time.Hour) claims := &Claims{ UserID: userID, Email: email, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(expirationTime), IssuedAt: jwt.NewNumericDate(time.Now()), }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(jwtKey) } func ValidateJWT(tokenString string) (*Claims, error) { claims := &Claims{} token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { return jwtKey, nil }) if err != nil || !token.Valid { return nil, err } return claims, nil } ``` ## 3. Sessiebeheer en Middleware ```go func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("token") if err != nil { if err == http.ErrNoCookie { http.Error(w, "Niet geautoriseerd", http.StatusUnauthorized) return } http.Error(w, "Bad request", http.StatusBadRequest) return } tokenStr := cookie.Value claims, err := ValidateJWT(tokenStr) if err != nil { http.Error(w, "Ongeldige token", http.StatusUnauthorized) return } // Voeg claims toe aan context ctx := context.WithValue(r.Context(), "user", claims) next.ServeHTTP(w, r.WithContext(ctx)) } } func RefreshToken(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("token") if err != nil { if err == http.ErrNoCookie { http.Error(w, "Geen token", http.StatusUnauthorized) return } http.Error(w, "Bad request", http.StatusBadRequest) return } tokenStr := cookie.Value claims, err := ValidateJWT(tokenStr) if err != nil { http.Error(w, "Ongeldige token", http.StatusUnauthorized) return } // Genereer nieuwe token als de oude bijna verloopt if time.Until(claims.ExpiresAt.Time) > 30*time.Minute { http.Error(w, "Token nog geldig", http.StatusBadRequest) return } newToken, err := GenerateJWT(claims.UserID, claims.Email) if err != nil { http.Error(w, "Kon token niet vernieuwen", http.StatusInternalServerError) return } http.SetCookie(w, &http.Cookie{ Name: "token", Value: newToken, Expires: time.Now().Add(24 * time.Hour), HttpOnly: true, Secure: true, // Alleen HTTPS SameSite: http.SameSiteStrictMode, }) w.Write([]byte("Token vernieuwd")) } ``` ## 4. Registratie en Login Handlers ```go func RegisterHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } email := r.FormValue("email") password := r.FormValue("password") // Valideer input if email == "" || password == "" { http.Error(w, "Email en wachtwoord vereist", http.StatusBadRequest) return } // Hash wachtwoord hashedPassword, err := HashPassword(password) if err != nil { http.Error(w, "Kon wachtwoord niet hashen", http.StatusInternalServerError) return } // Sla gebruiker op in database userID, err := SaveUser(email, hashedPassword) if err != nil { http.Error(w, "Kon gebruiker niet aanmaken", http.StatusInternalServerError) return } // Genereer JWT token, err := GenerateJWT(userID, email) if err != nil { http.Error(w, "Kon token niet genereren", http.StatusInternalServerError) return } http.SetCookie(w, &http.Cookie{ Name: "token", Value: token, Expires: time.Now().Add(24 * time.Hour), HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, }) w.WriteHeader(http.StatusCreated) w.Write([]byte("Gebruiker aangemaakt")) } func LoginHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } email := r.FormValue("email") password := r.FormValue("password") user, err := GetUserByEmail(email) if err != nil { http.Error(w, "Ongeldige credentials", http.StatusUnauthorized) return } if !CheckPasswordHash(password, user.PasswordHash) { http.Error(w, "Ongeldige credentials", http.StatusUnauthorized) return } token, err := GenerateJWT(user.ID, user.Email) if err != nil { http.Error(w, "Kon token niet genereren", http.StatusInternalServerError) return } http.SetCookie(w, &http.Cookie{ Name: "token", Value: token, Expires: time.Now().Add(24 * time.Hour), HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, }) w.Write([]byte("Succesvol ingelogd")) } ``` ## 5. Beveiligingsmaatregelen ```go func SecurityHeadersMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Frame-Options", "DENY") w.Header().Set("X-XSS-Protection", "1; mode=block") w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains") next.ServeHTTP(w, r) }) } ``` ## 6. Main Applicatie ```go func main() { mux := http.NewServeMux() // Routes mux.HandleFunc("/register", RegisterHandler) mux.HandleFunc("/login", LoginHandler) mux.HandleFunc("/refresh", RefreshToken) mux.HandleFunc("/protected", AuthMiddleware(ProtectedHandler)) // Beveiligde middleware toevoegen protectedMux := SecurityHeadersMiddleware(mux) // Start server fmt.Println("Server draait op :8080") http.ListenAndServe(":8080", protectedMux) } func ProtectedHandler(w http.ResponseWriter, r *http.Request) { user := r.Context().Value("user").(*Claims) w.Write([]byte("Welkom " + user.Email)) } ``` ## Belangrijke beveiligingstips: 1. **Environment variables**: Gebruik nooit hardcoded secrets 2. **HTTPS**: Altijd SSL/TLS gebruiken in productie 3. **Rate limiting**: Voeg rate limiting toe voor login pogingen 4. **CSRF protection**: Implementeer CSRF tokens voor state-changing requests 5. **Input validation**: Valideer alle gebruikersinput 6. **Secure cookies**: HttpOnly, Secure, en SameSite flags 7. **Token expiration**: Korte token levensduur met refresh mechanisme Dit is een solide basis voor een veilig authenticatiesysteem in Go!
error: Generation failed [deepseek] prompt_id=1403 locale=en err=DeepSeek connection/timeout