package form import ( "crypto/rand" "crypto/subtle" "encoding/base64" "net/http" "time" ) const ( csrfCookieName = "_csrf" csrfFieldName = "_csrf" csrfTTL = time.Minute * 30 csrfTokenSize = 32 ) /* csrfToken generates and configures a new double-submit CSRF token */ func csrfToken(w http.ResponseWriter, r *http.Request, secure bool) string { /* get csrf cookie */ cookie, err := r.Cookie(csrfCookieName) if err != nil { /* cookie does not yet exist, generate a new token */ b := make([]byte, csrfTokenSize) rand.Read(b) token := base64.RawURLEncoding.EncodeToString(b) /* render new cookie */ http.SetCookie(w, &http.Cookie{ Name: csrfCookieName, Value: token, Path: "/", HttpOnly: false, SameSite: http.SameSiteLaxMode, Secure: secure, MaxAge: int(csrfTTL.Seconds()), }) return token } /* return existing csrf token */ return cookie.Value } /* csrfVerify checks if double-submit CSRF token is valid */ func csrfVerify(r *http.Request) bool { /* get csrf form field value */ formToken := r.PostFormValue(csrfFieldName) if formToken == "" { return false } /* get csrf cookie */ cookie, err := r.Cookie(csrfCookieName) if err != nil { return false } /* compare the results */ return subtle.ConstantTimeCompare([]byte(formToken), []byte(cookie.Value)) == 1 }