csrf.go 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. package form
  2. import (
  3. "crypto/rand"
  4. "crypto/subtle"
  5. "encoding/base64"
  6. "net/http"
  7. "time"
  8. )
  9. const (
  10. csrfCookieName = "_csrf"
  11. csrfFieldName = "_csrf"
  12. csrfTTL = time.Minute * 30
  13. csrfTokenSize = 32
  14. )
  15. /* csrfToken generates and configures a new double-submit CSRF token */
  16. func csrfToken(w http.ResponseWriter, r *http.Request, secure bool) string {
  17. /* get csrf cookie */
  18. cookie, err := r.Cookie(csrfCookieName)
  19. if err != nil {
  20. /* cookie does not yet exist, generate a new token */
  21. b := make([]byte, csrfTokenSize)
  22. rand.Read(b)
  23. token := base64.RawURLEncoding.EncodeToString(b)
  24. /* render new cookie */
  25. http.SetCookie(w, &http.Cookie{
  26. Name: csrfCookieName,
  27. Value: token,
  28. Path: "/",
  29. HttpOnly: false,
  30. SameSite: http.SameSiteLaxMode,
  31. Secure: secure,
  32. MaxAge: int(csrfTTL.Seconds()),
  33. })
  34. return token
  35. }
  36. /* return existing csrf token */
  37. return cookie.Value
  38. }
  39. /* csrfVerify checks if double-submit CSRF token is valid */
  40. func csrfVerify(r *http.Request) bool {
  41. /* get csrf form field value */
  42. formToken := r.PostFormValue(csrfFieldName)
  43. if formToken == "" {
  44. return false
  45. }
  46. /* get csrf cookie */
  47. cookie, err := r.Cookie(csrfCookieName)
  48. if err != nil {
  49. return false
  50. }
  51. /* compare the results */
  52. return subtle.ConstantTimeCompare([]byte(formToken), []byte(cookie.Value)) == 1
  53. }