Skip to content

Commit

Permalink
Encrypt the CSRF cookie
Browse files Browse the repository at this point in the history
  • Loading branch information
Nick Meves committed Jan 1, 2021
1 parent b61269d commit b912e65
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 14 deletions.
42 changes: 36 additions & 6 deletions pkg/cookies/csrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,28 +110,38 @@ func (c CSRF) ClearCookie(rw http.ResponseWriter, req *http.Request) {
))
}

// EncodeCookie MessagePack encodes the CSRF and then creates a signed
// cookie value
// EncodeCookie MessagePack encodes and encrypts the CSRF and then creates a
// signed cookie value
func (c CSRF) EncodeCookie() (string, error) {
packed, err := msgpack.Marshal(c)
if err != nil {
return "", fmt.Errorf("error marshalling CSRF to msgpack: %v", err)
}

return encryption.SignedValue(c.cookieOpts.Secret, c.CookieName(), packed, now())
encrypted, err := encrypt(packed, c.cookieOpts)
if err != nil {
return "", err
}

return encryption.SignedValue(c.cookieOpts.Secret, c.CookieName(), encrypted, now())
}

// DecodeCSRFCookie validates the signature and decodes a CSRF cookie into
// a CSRF struct
// DecodeCSRFCookie validates the signature then decrypts and decodes a CSRF
// cookie into a CSRF struct
func DecodeCSRFCookie(cookie *http.Cookie, opts *options.Cookie) (*CSRF, error) {
val, _, ok := encryption.Validate(cookie, opts.Secret, opts.Expire)
if !ok {
return nil, errors.New("CSRF cookie failed validation")
}

decrypted, err := decrypt(val, opts)
if err != nil {
return nil, err
}

// Valid cookie, Unmarshal the CSRF
csrf := &CSRF{cookieOpts: opts}
err := msgpack.Unmarshal(val, csrf)
err = msgpack.Unmarshal(decrypted, csrf)
if err != nil {
return nil, fmt.Errorf("error unmarshalling data to CSRF: %v", err)
}
Expand All @@ -148,3 +158,23 @@ func (c CSRF) CookieName() string {
func csrfCookieName(opts *options.Cookie) string {
return fmt.Sprintf("%v_csrf", opts.Name)
}

func encrypt(data []byte, opts *options.Cookie) ([]byte, error) {
cipher, err := makeCipher(opts)
if err != nil {
return nil, err
}
return cipher.Encrypt(data)
}

func decrypt(data []byte, opts *options.Cookie) ([]byte, error) {
cipher, err := makeCipher(opts)
if err != nil {
return nil, err
}
return cipher.Decrypt(data)
}

func makeCipher(opts *options.Cookie) (encryption.Cipher, error) {
return encryption.NewCFBCipher([]byte(opts.Secret))
}
14 changes: 6 additions & 8 deletions pkg/cookies/csrf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,15 @@ var _ = Describe("CSRF Cookie Tests", func() {
It("adds the encoded CSRF cookie to a ResponseWriter", func() {
rw := httptest.NewRecorder()

expectedValue, err := csrf.EncodeCookie()
err := csrf.SetCookie(rw, req)
Expect(err).ToNot(HaveOccurred())

err = csrf.SetCookie(rw, req)
Expect(err).ToNot(HaveOccurred())

Expect(rw.Header().Get("Set-Cookie")).To(Equal(
Expect(rw.Header().Get("Set-Cookie")).To(ContainSubstring(
fmt.Sprintf("%s=", csrf.CookieName()),
))
Expect(rw.Header().Get("Set-Cookie")).To(ContainSubstring(
fmt.Sprintf(
"%s=%s; Path=%s; Domain=%s; Expires=%s; HttpOnly; Secure; SameSite",
csrf.CookieName(),
expectedValue,
"; Path=%s; Domain=%s; Expires=%s; HttpOnly; Secure; SameSite",
cookiePath,
cookieDomain,
testCookieExpires(now().Add(cookieOpts.Expire)),
Expand Down

0 comments on commit b912e65

Please sign in to comment.