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

try_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 ... more
generate_helper
disclaimerOnPageApi image_legal_disclaimer...

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