Package gorilla/securecookie encodes and decodes authenticated and optionally encrypted cookie values for Go web applications.

Overview

securecookie

GoDoc Build Status Sourcegraph

securecookie encodes and decodes authenticated and optionally encrypted cookie values.

Secure cookies can't be forged, because their values are validated using HMAC. When encrypted, the content is also inaccessible to malicious eyes. It is still recommended that sensitive data not be stored in cookies, and that HTTPS be used to prevent cookie replay attacks.

Examples

To use it, first create a new SecureCookie instance:

// Hash keys should be at least 32 bytes long
var hashKey = []byte("very-secret")
// Block keys should be 16 bytes (AES-128) or 32 bytes (AES-256) long.
// Shorter keys may weaken the encryption used.
var blockKey = []byte("a-lot-secret")
var s = securecookie.New(hashKey, blockKey)

The hashKey is required, used to authenticate the cookie value using HMAC. It is recommended to use a key with 32 or 64 bytes.

The blockKey is optional, used to encrypt the cookie value -- set it to nil to not use encryption. If set, the length must correspond to the block size of the encryption algorithm. For AES, used by default, valid lengths are 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.

Strong keys can be created using the convenience function GenerateRandomKey(). Note that keys created using GenerateRandomKey() are not automatically persisted. New keys will be created when the application is restarted, and previously issued cookies will not be able to be decoded.

Once a SecureCookie instance is set, use it to encode a cookie value:

func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
	value := map[string]string{
		"foo": "bar",
	}
	if encoded, err := s.Encode("cookie-name", value); err == nil {
		cookie := &http.Cookie{
			Name:  "cookie-name",
			Value: encoded,
			Path:  "/",
			Secure: true,
			HttpOnly: true,
		}
		http.SetCookie(w, cookie)
	}
}

Later, use the same SecureCookie instance to decode and validate a cookie value:

func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
	if cookie, err := r.Cookie("cookie-name"); err == nil {
		value := make(map[string]string)
		if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil {
			fmt.Fprintf(w, "The value of foo is %q", value["foo"])
		}
	}
}

We stored a map[string]string, but secure cookies can hold any value that can be encoded using encoding/gob. To store custom types, they must be registered first using gob.Register(). For basic types this is not needed; it works out of the box. An optional JSON encoder that uses encoding/json is available for types compatible with JSON.

Key Rotation

Rotating keys is an important part of any security strategy. The EncodeMulti and DecodeMulti functions allow for multiple keys to be rotated in and out. For example, let's take a system that stores keys in a map:

// keys stored in a map will not be persisted between restarts
// a more persistent storage should be considered for production applications.
var cookies = map[string]*securecookie.SecureCookie{
	"previous": securecookie.New(
		securecookie.GenerateRandomKey(64),
		securecookie.GenerateRandomKey(32),
	),
	"current": securecookie.New(
		securecookie.GenerateRandomKey(64),
		securecookie.GenerateRandomKey(32),
	),
}

Using the current key to encode new cookies:

func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
	value := map[string]string{
		"foo": "bar",
	}
	if encoded, err := securecookie.EncodeMulti("cookie-name", value, cookies["current"]); err == nil {
		cookie := &http.Cookie{
			Name:  "cookie-name",
			Value: encoded,
			Path:  "/",
		}
		http.SetCookie(w, cookie)
	}
}

Later, decode cookies. Check against all valid keys:

func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
	if cookie, err := r.Cookie("cookie-name"); err == nil {
		value := make(map[string]string)
		err = securecookie.DecodeMulti("cookie-name", cookie.Value, &value, cookies["current"], cookies["previous"])
		if err == nil {
			fmt.Fprintf(w, "The value of foo is %q", value["foo"])
		}
	}
}

Rotate the keys. This strategy allows previously issued cookies to be valid until the next rotation:

func Rotate(newCookie *securecookie.SecureCookie) {
	cookies["previous"] = cookies["current"]
	cookies["current"] = newCookie
}

License

BSD licensed. See the LICENSE file for details.

Issues
  • Improve Decode against timing attacks

    Improve Decode against timing attacks

    The current implementation of Decode allows very easily with timing attacks to find out which error occurred. I improved it, but there are probably still some room for improvement.

    opened by abduelhamit 14
  • Make GenerateRandomKey panic on error

    Make GenerateRandomKey panic on error

    Previously GenerateRandomKey returned nil if it failed to read random bytes from crypto/rand Reader. A quick GitHub code search:

    https://github.com/search?utf8=%E2%9C%93&q=securecookie.GenerateRandomKey&type=Code&ref=searchresults

    reveals that most people don't bother to check the return value, thus, if their random generator fails for some reason, they'll get empty keys.

    We fix this by making GenerateRandomKey panic on error, which is a common and safe way to deal with such cases if there's no error return.

    enhancement 
    opened by dchest 13
  • Save Encoder/Decoder: 9x fewer allocs; 6x faster.

    Save Encoder/Decoder: 9x fewer allocs; 6x faster.

    This PR is meant to address performance and allocation overhead. Per the gob/encoding documentation:

    "...[it] is most efficient when a single Encoder is used to transmit a stream of values, amortizing the cost of compilation."

    The existing implementation created and destroyed gob.Encoders and gob.Decoders on every call to serialize and deserialize, respectively.

    I changed the SecureCookie object to maintain a buffer, encoder, and decoder to re-use. There is a significant difference in speed and memory allocation overhead:

    | Implementation | time/op | mem/op | allocs/op | | --- | :-: | :-: | :-: | | Old | 75,275 ns | 21,396 B | 369 | | New | 17,843 ns | 3,475 B | 39 |

    (I've added the benchmark in the testing file for you to see for yourself.)

    The downside here is that the SecureCookie object has to lock around serialization calls. This could potentially be improved by maintaining an array of buffers and doing fine-grained locking. (But then we would have a really fat struct.)

    Looking forward to your comments, Phil

    Review on Reviewable

    opened by philhofer 12
  • Maybe the performance of the function GenerateRandomKey can be greatly improved

    Maybe the performance of the function GenerateRandomKey can be greatly improved

    Maybe using "crypto/rand" to generate the key is not efficient as mentioned in: http://stackoverflow.com/questions/12771930/what-is-the-fastest-way-to-generate-a-long-random-string-in-go

    I think maybe you can adopt some points from https://github.com/dustin/randbo/blob/master/randbo.go .

    Thank you very much.

    opened by bigradish 10
  • securecookie: base64 decode failed - caused by: illegal base64 data at input byte 216

    securecookie: base64 decode failed - caused by: illegal base64 data at input byte 216

    Code

    Session store

    secret := securecookie.GenerateRandomKey(64)
    if secret == nil {
    	glg.Fatalf("The system random number generator failed")
    }
    srv.sessionStore = sessions.NewCookieStore(secret)
    

    Session get

    func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
    	sess, err := s.sessionStore.Get(r, sessionCookieName)
    	glg.Infof("Session is new: %v", sess.IsNew)
    	if err != nil {
    		glg.Errorf("read session: %v", err)
    		sess, err = s.sessionStore.New(r, sessionCookieName)
    		if err != nil {
    			glg.Errorf("new session: %v", err)
    			return
    		}
    	}
    }
    

    Output

    2018-08-30 16:59:24     [INFO]: Session is new: true
    2018-08-30 16:52:10     [ERR]:  read session: securecookie: base64 decode failed - caused by: illegal base64 data at input byte 216
    2018-08-30 16:52:10     [ERR]:  new session: securecookie: base64 decode failed - caused by: illegal base64 data at input byte 216
    

    At the point where this error occurs, the session is new and no data has been written into it's Values whatsoever. I can't explain this error, and hoped maybe one of you can help me here? I'd be happy to provide further information.

    question stale 
    opened by ghost 9
  • add more compact encoding

    add more compact encoding

    Current encoding does Base64 twice against payload because of intermediate text encoding. And it produces too large mac (256bit) while 128bit is more than enough.

    Add "compact" mode which uses binary encoding for message with single Base64 pass and 128bit hmac output (at max).

        TestSecureCookie: securecookie_test.go:48: i 0 len 184                                                         
        TestSecureCookie: securecookie_test.go:48: i 1 len 128                                                         
        TestSecureCookie: securecookie_test.go:48: i 2 len 188                                                         
        TestSecureCookie: securecookie_test.go:48: i 3 len 128                                                         
        TestSecureCookie: securecookie_test.go:48: i 4 len 188                                                         
        TestSecureCookie: securecookie_test.go:48: i 5 len 128                                                         
        TestSecureCookie: securecookie_test.go:48: i 6 len 188                                                         
        TestSecureCookie: securecookie_test.go:48: i 7 len 128                                                         
        TestSecureCookie: securecookie_test.go:48: i 8 len 188                                                         
        TestSecureCookie: securecookie_test.go:48: i 9 len 128                                                         
    
    opened by funny-falcon 8
  • Make errors more distinguishable

    Make errors more distinguishable

    Prior to this commit, this library raised errors either mostly using errors.New() or directly passing through error values from underlying libraries. This made it difficult for clients to respond correctly to the errors that were returned.

    This becomes particularly problematic when securecookie is used together with gorilla/sessions. From an operations standpoint, you often want to log different errors when the client simply provides an invalid auth cookie, versus an I/O error fetching data from the session store. The former probably indicates an expired timestamp or similar client error; the latter indicates a possible failure in a backend database.

    This commit introduces a public Error interface, which is now returned consistently on all errors, and can be used to distinguish between implementation errors (IsUsage() and IsInternal()) and failed validation of user input (IsDecode()).

    See also discussion on pull requests #9 and #24: https://github.com/gorilla/securecookie/pull/9 https://github.com/gorilla/securecookie/pull/24

    Some interface comments on other API functions have been clarified and updated to harmonize with the new error interfaces.

    opened by keunwoo 7
  • Cookie not returned from the browser

    Cookie not returned from the browser

    Hello,

    I am having issues using securecookie. When I encode a value and send it to the browser, it is sometimes not returning it back. Seems to me like the browser doesn't like some of the characters in the encoded cookie value. I am using Google Chrome, up to date.

    Tried replacing base64 with base32.StdEncoding in this package and also replacing the padding = with 0, which is ok for base32.StdEncoding, and it all started working.

    So, I am basically asking where the issues is. How come this package is working for other people?

    In case I don't want to fork this package, what am I supposed to do? Encode the value returned from securecookie with base32? That will only increase the cookie size, although it is not really dramatic for my use case...

    Thanks!

    question 
    opened by tchap 6
  • Exposing the cookie timestamp

    Exposing the cookie timestamp

    I have a use case where I want to refresh the cookie and its data after a certain time period. This period is much shorter than the maximum age of the cookie and the cookie's validity shouldn't be affected by this shorter refresh cycle.

    I could include a timestamp inside my cookie data, but that seems highly redundant as there is already a HMAC verified timestamp in the cookie and I would rather save some bandwidth. Unfortunately this timestamp isn't exposed in any way currently, so this is where my patch comes in.

    An additional return value from the Decode method would be the safest & most straightforward solution. It would break API compatibility however, so probably not that likely to get merged.

    I gathered from issue #14 that thread safety isn't a goal of this library. This opened up another fairly easy solution, which I have implemented. Successful enough calls to Decode will update the new LastTimestamp property of the main SecureCookie struct instance with the cookie's timestamp.

    wontfix 
    opened by xStrom 6
  • Added support for encoding/json

    Added support for encoding/json

    Added a new Encoder interface with serialize and deserialize methods. The existing encoding/gob remains the default for compatibility reasons. Package users who wish to use the (often faster) encoding/json package can do so at the cost of some extra LOC for custom types.

    At the moment the interface and its methods are private as I wanted to avoid expanding the public API too much. If there's a desire to have it public so that others can satisfy Encoder in their own code then I'm happy to change it.

    I also added a new JSON test based on the existing gob test for completeness.

    opened by elithrar 6
  • How to handle error

    How to handle error "securecookie: expired timestamp"

    I get error securecookie: expired timestamp even though I don't set an expiration date on the cookie. (I suspect there's a date in the encrypted cookie.) Here is my logic:

    	co, err := sc.Encode("user", user.ID)
    	if err != nil {
    		return errors.Wrap(err, "failed to encode the token")
    	}
    
    	http.SetCookie(w, &http.Cookie{
    		Name:  "user",
    		Path:  "/",
    		Value: co,
    	})
    

    What am I supposed to do with this error?

    The errTimestampExpired is not exported from the package, so that doesn't give me a good way to check whether an error is indeed expiration error. What should a server do when they get this error? Clear cookies to unblock the user?

    stale 
    opened by ahmetb 5
  • corresponding Java implementation

    corresponding Java implementation

    Excuse me, Does this algorithm have a corresponding Java implementation?

    There is a Go Projection encode cookie by using this algorithm, and now , I want decode the cookie in Java Projection.

    I can not find a java lib about decoding cookie by using this algorithm.

    Please Help Me~~~

    question 
    opened by zhao1-1 2
  • Add compact encoding (v2)

    Add compact encoding (v2)

    Current encoding does Base64 twice against payload because of intermediate text encoding. Also it adds 16byte nonce to value (and it is also expanded twice by Base64) and 32byte MAC with default settings. Total overhead of added data is (12+32+(16*4/3))*4/3 == 87 bytes, and value is expanded in (4/3)*(4/3)=1.77 times.

    Summary of Changes

    This PR adds compact encoding for securecookie:

    • value is passed through Base64 only once together with MAC and time
    • there is no separate nonce. MAC is calculated on plaintext + time (with submillisecond granularity) and then used as nonce for stream cipher.
    • migration is easy because it may decode both versions guessing by first base64 byte
    • algorithms are fixed to Blake2s and Chacha20 cause they are proven to be secure and fast on all common architectures (32/64 bit, appengine).

    Total overhead data is (1+15+8)*4/3 = 32 bytes. Value expanded only once in 1.33 times.

    Note: MAC is 15byte (120bit) which is certainly enough for this use case.

    It saves a lot of cpu time and allocations:

    BenchmarkLegacyEncode-8     239144   4504 ns/op  3445 B/op   21 allocs/op
    BenchmarkLegacyEncode-8     261038   4499 ns/op  3442 B/op   21 allocs/op
    BenchmarkCompactEncode-8    933446   1304 ns/op   721 B/op    4 allocs/op
    BenchmarkCompactEncode-8    927328   1331 ns/op   721 B/op    4 allocs/op
    BenchmarkLegacyDecode-8     298273   3923 ns/op  2312 B/op   17 allocs/op
    BenchmarkLegacyDecode-8     298401   3944 ns/op  2367 B/op   17 allocs/op
    BenchmarkCompactDecode-8    806112   1359 ns/op   465 B/op    3 allocs/op
    BenchmarkCompactDecode-8    905617   1348 ns/op   471 B/op    3 allocs/op
    
    enhancement 
    opened by funny-falcon 12
  • Update README.md

    Update README.md

    Typo in Example Code?

    Fixes # Appears to be typo in example code.

    Summary of Changes

    1. change s2 to s

    PS: Make sure your PR includes/updates tests! If you need help with this part, just ask!

    opened by btsteve 1
  • difference to JWT

    difference to JWT

    Not really a bug or a feature request - but a request for clarification in the README.

    Why would one use the this project over JWT? JWT also supports signing and encryption - and is a standard.

    I am not making a case for either - but it would be nice to read a position on this.

    question 
    opened by tcurdt 9
  • [feature] Support Nonce Misuse-Resistant Authenticated Encryption

    [feature] Support Nonce Misuse-Resistant Authenticated Encryption

    Is your feature request related to a problem? Please describe.

    The current algorithms available to securecookie are susceptible to nonce-reuse issues under certain conditions. I know this is very much on the radar 1,2 of the maintainers, but the effort seems tied to a v2 which I'm not sure of the status of.

    Describe the solution you'd like

    I'd like for sessions to use a non misuse-resistant algorithm. Options include:

    XChaCha20-Poly1305 seems like the best current option. It currently exists in /x/crypto, implements the aead interface, is relatively fast (no AES-NI 😭 ), and is ubiquitous.

    Describe alternatives you've considered

    Reinvent the wheel and reimplement/fork my own sessions package. Which, you know. Meh.

    Of course, I'd be happy to help but didn't want to step on toes if this is part of a larger effort.

    feature request 
    opened by desimone 1
  • Expose error types?

    Expose error types?

    It seems like the ideal behavior for a cookie w/ an expired timestamp would be for me to consider it equivalent to http.ErrNoCookie, but right now I can't find a clean way to check for that, since the types of errors are all private.

    Am I missing a better workflow or existing clean way to check for this?

    proposal 
    opened by akerl 3
Releases(v1.1.1)
  • v1.1.1(Feb 23, 2018)

    Tagging with a proper semantic version.

    CHANGELOG

    e59506c README.md: Add sourcegraph badge fa5329f [bugfix] Fix NopDecoder c13558c Add fuzz testing corpus. 422e448 travis.yml: add go1.7 ff35634 Merge pull request #39 from 0x434D53/master f5b3726 Update Readme: Added HttpOnly, Secure flags for setting the cookie

    Source code(tar.gz)
    Source code(zip)
Owner
Gorilla Web Toolkit
Gorilla is a web toolkit for the Go programming language that provides useful, composable packages for writing HTTP-based applications.
Gorilla Web Toolkit
Cookie - Cookie helper functions for golang

Cookie Cookie helper functions. package main import ( "net/http" "github.co

infinite loop 0 Feb 10, 2022
Authenticated and encrypted API tokens using modern crypto

Branca Token Authenticated and encrypted API tokens using modern crypto. What? Branca is a secure, easy to use token format which makes it hard to sho

Mika Tuupola 183 May 14, 2022
:key: Secure alternative to JWT. Authenticated Encrypted API Tokens for Go.

branca branca is a secure alternative to JWT, This implementation is written in pure Go (no cgo dependencies) and implements the branca token specific

Wesley Hill 166 Mar 19, 2022
Authenticated encrypted API tokens (IETF XChaCha20-Poly1305 AEAD) for Golang

branca.go is branca token specification implementation for Golang 1.15+.

ESSENTIAL KAOS 34 Apr 19, 2022
golang csrf react example, using gorilla/mux and gorilla/mux

Demo REST backend Gorilla csrf middleware and Js frontend Use gorilla/mux and gorilla/csrf How to run open goland IDE, run middleware_test.go by click

Mike Cat 0 Feb 2, 2022
Fast, secure and efficient secure cookie encoder/decoder

Encode and Decode secure cookies This package provides functions to encode and decode secure cookie values. A secure cookie has its value ciphered and

Christophe Meessen 56 May 18, 2022
Advent of Code Input Loader, provide a session cookie and a problem date, returns a string or []byte of the input

Advent of Code Get (aocget) A small lib to download your puzzle input for a given day. Uses your session token to authenticate to obtain your personal

Adrian 0 Dec 9, 2021
Goauth - Basic username password cookie based authentication with Go Lang

goauth [WIP] Basic username password cookie based authentication with Go Lang Overview Use a Postgres DB to store Sign-in and Sign-up info Redis for c

Joseph Chen 0 Jan 4, 2022
Cocos2d-x texture unpacker, primarily for Cookie Run.

boofunpack Cocos2d-x texture unpacker, primarily for Cookie Run: OvenBreak and Cookie Run for Kakao/LINE (though it likely works for other .plist form

null 2 Mar 8, 2022
Package goth provides a simple, clean, and idiomatic way to write authentication packages for Go web applications.

Goth: Multi-Provider Authentication for Go Package goth provides a simple, clean, and idiomatic way to write authentication packages for Go web applic

Mark Bates 3.7k May 16, 2022
Aegis To KeePass - A simple tool to convert exported (and encrypted) Aegis database to standalone KeePass

ATP - Aegis to KeePass A simple tool to convert exported (and encrypted) Aegis d

Nikitka 2 Jan 24, 2022
Certificate authority and access plane for SSH, Kubernetes, web applications, and databases

Teleport is an identity-aware, multi-protocol access proxy which understands SSH, HTTPS, Kubernetes API, MySQL and PostgreSQL wire protocols.

Teleport 11.8k May 22, 2022
Minimalistic RBAC package for Go applications

RBAC Overview RBAC is a package that makes it easy to implement Role Based Access Control (RBAC) models in Go applications. Download To download this

Zack Patrick 95 Apr 22, 2022
jwt package for gin go applications

gin-jwt jwt package for gin go applications Usage Download using go module: go get github.com/ennaque/gin-jwt Import it in your code: import gwt "gith

Igor Volkov 2 Apr 21, 2022
This package provides json web token (jwt) middleware for goLang http servers

jwt-auth jwt auth middleware in goLang. If you're interested in using sessions, checkout my sessions library! README Contents: Quickstart Performance

Adam Hanna 216 May 13, 2022
The mep-agent module provides proxy services for 3rd applications to MEP.

Mep-Agent Introduction Mep-Agent is a middleware that provides proxy services for third-party apps. It can help apps, which do not implement the ETSI

EdgeGallery 21 Mar 9, 2022
A library for Go client applications that need to perform OAuth authorization against a server

oauth-0.8.0.zip oauth A library for Go client applications that need to perform OAuth authorization against a server, typically GitHub.com. Traditiona

tigressma 1 Oct 13, 2021
Go-Guardian is a golang library that provides a simple, clean, and idiomatic way to create powerful modern API and web authentication.

❗ Cache package has been moved to libcache repository Go-Guardian Go-Guardian is a golang library that provides a simple, clean, and idiomatic way to

Sanad Haj Yahya 366 May 14, 2022
A simple and lightweight library for creating, formatting, manipulating, signing, and validating JSON Web Tokens in Go.

GoJWT - JSON Web Tokens in Go GoJWT is a simple and lightweight library for creating, formatting, manipulating, signing and validating Json Web Tokens

Toby 5 Feb 7, 2022