La Cross-Site Request Forgery (CSRF) è una vulnerabilità che consente a un attaccante di indurre un utente autenticato a eseguire azioni indesiderate su un'applicazione web. In questo articolo vedremo come implementare una semplice protezione CSRF da zero in Go.
1. Concetto base
Il principio è semplice: per ogni richiesta mutante (POST, PUT, DELETE), si richiede un token CSRF che deve essere inviato dall'utente e verificato sul server.
2. Generazione del token
Il token CSRF viene generato e memorizzato nella sessione dell'utente. Viene anche incluso nei form HTML.
func generateCSRFToken() (string, error) {
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b), nil
}
3. Aggiunta del token alla sessione
Quando si crea una nuova sessione o si accede a una pagina protetta, si genera il token CSRF se non esiste già.
func ensureCSRFToken(w http.ResponseWriter, r *http.Request) string {
session, _ := store.Get(r, "session-name")
token, ok := session.Values["csrf_token"].(string)
if !ok || token == "" {
token, _ = generateCSRFToken()
session.Values["csrf_token"] = token
session.Save(r, w)
}
return token
}
4. Inclusione del token nel form HTML
Il token CSRF va incluso come campo nascosto in ogni form HTML.
<form method="POST" action="/submit">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<input type="text" name="message">
<button type="submit">Invia</button>
</form>
5. Verifica del token lato server
Al momento della ricezione della richiesta, si confronta il token inviato con quello salvato nella sessione.
func validateCSRFToken(r *http.Request) bool {
session, _ := store.Get(r, "session-name")
storedToken, _ := session.Values["csrf_token"].(string)
submittedToken := r.FormValue("csrf_token")
return storedToken != "" && submittedToken == storedToken
}
6. Applicazione pratica
All'interno del tuo handler POST, verifica il token prima di procedere:
func handleSubmit(w http.ResponseWriter, r *http.Request) {
if !validateCSRFToken(r) {
http.Error(w, "Invalid CSRF token", http.StatusForbidden)
return
}
// continua con l'elaborazione della richiesta
}
Conclusione
Abbiamo visto come costruire una semplice ma efficace protezione CSRF in Go. Questo approccio può essere ulteriormente migliorato utilizzando token "double submit" o integrandosi con librerie di sessione più avanzate.