README

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().

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.

License

BSD licensed. See the LICENSE file for details.

Expand ▾ Collapse ▴

Documentation

Overview

    Package 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.

    To use it, first create a new SecureCookie instance:

    var hashKey = []byte("very-secret")
    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().

    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:  "/",
    		}
    		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.

    Index

    Constants

    This section is empty.

    Variables

    View Source
    var (
    
    	// ErrMacInvalid indicates that cookie decoding failed because the HMAC
    	// could not be extracted and verified.  Direct use of this error
    	// variable is deprecated; it is public only for legacy compatibility,
    	// and may be privatized in the future, as it is rarely useful to
    	// distinguish between this error and other Error implementations.
    	ErrMacInvalid = cookieError{/* contains filtered or unexported fields */}
    )

    Functions

    func DecodeMulti

    func DecodeMulti(name string, value string, dst interface{}, codecs ...Codec) error

      DecodeMulti decodes a cookie value using a group of codecs.

      The codecs are tried in order. Multiple codecs are accepted to allow key rotation.

      On error, may return a MultiError.

      func EncodeMulti

      func EncodeMulti(name string, value interface{}, codecs ...Codec) (string, error)

        EncodeMulti encodes a cookie value using a group of codecs.

        The codecs are tried in order. Multiple codecs are accepted to allow key rotation.

        On error, may return a MultiError.

        func GenerateRandomKey

        func GenerateRandomKey(length int) []byte

          GenerateRandomKey creates a random key with the given length in bytes. On failure, returns nil.

          Callers should explicitly check for the possibility of a nil return, treat it as a failure of the system random number generator, and not continue.

          Types

          type Codec

          type Codec interface {
          	Encode(name string, value interface{}) (string, error)
          	Decode(name, value string, dst interface{}) error
          }

            Codec defines an interface to encode and decode cookie values.

            func CodecsFromPairs

            func CodecsFromPairs(keyPairs ...[]byte) []Codec

              CodecsFromPairs returns a slice of SecureCookie instances.

              It is a convenience function to create a list of codecs for key rotation. Note that the generated Codecs will have the default options applied: callers should iterate over each Codec and type-assert the underlying *SecureCookie to change these.

              Example:

              codecs := securecookie.CodecsFromPairs(
                   []byte("new-hash-key"),
                   []byte("new-block-key"),
                   []byte("old-hash-key"),
                   []byte("old-block-key"),
               )
              
              // Modify each instance.
              for _, s := range codecs {
                     if cookie, ok := s.(*securecookie.SecureCookie); ok {
                         cookie.MaxAge(86400 * 7)
                         cookie.SetSerializer(securecookie.JSONEncoder{})
                         cookie.HashFunc(sha512.New512_256)
                     }
                 }
              

              type Error

              type Error interface {
              	error
              
              	// IsUsage returns true for errors indicating the client code probably
              	// uses this library incorrectly.  For example, the client may have
              	// failed to provide a valid hash key, or may have failed to configure
              	// the Serializer adequately for encoding value.
              	IsUsage() bool
              
              	// IsDecode returns true for errors indicating that a cookie could not
              	// be decoded and validated.  Since cookies are usually untrusted
              	// user-provided input, errors of this type should be expected.
              	// Usually, the proper action is simply to reject the request.
              	IsDecode() bool
              
              	// IsInternal returns true for unexpected errors occurring in the
              	// securecookie implementation.
              	IsInternal() bool
              
              	// Cause, if it returns a non-nil value, indicates that this error was
              	// propagated from some underlying library.  If this method returns nil,
              	// this error was raised directly by this library.
              	//
              	// Cause is provided principally for debugging/logging purposes; it is
              	// rare that application logic should perform meaningfully different
              	// logic based on Cause.  See, for example, the caveats described on
              	// (MultiError).Cause().
              	Cause() error
              }

                Error is the interface of all errors returned by functions in this library.

                type GobEncoder

                type GobEncoder struct{}

                  GobEncoder encodes cookie values using encoding/gob. This is the simplest encoder and can handle complex types via gob.Register.

                  func (GobEncoder) Deserialize

                  func (e GobEncoder) Deserialize(src []byte, dst interface{}) error

                    Deserialize decodes a value using gob.

                    func (GobEncoder) Serialize

                    func (e GobEncoder) Serialize(src interface{}) ([]byte, error)

                      Serialize encodes a value using gob.

                      type JSONEncoder

                      type JSONEncoder struct{}

                        JSONEncoder encodes cookie values using encoding/json. Users who wish to encode complex types need to satisfy the json.Marshaller and json.Unmarshaller interfaces.

                        func (JSONEncoder) Deserialize

                        func (e JSONEncoder) Deserialize(src []byte, dst interface{}) error

                          Deserialize decodes a value using encoding/json.

                          func (JSONEncoder) Serialize

                          func (e JSONEncoder) Serialize(src interface{}) ([]byte, error)

                            Serialize encodes a value using encoding/json.

                            type MultiError

                            type MultiError []error

                              MultiError groups multiple errors.

                              func (MultiError) Cause

                              func (m MultiError) Cause() error

                                Cause returns nil for MultiError; there is no unique underlying cause in the general case.

                                Note: we could conceivably return a non-nil Cause only when there is exactly one child error with a Cause. However, it would be brittle for client code to rely on the arity of causes inside a MultiError, so we have opted not to provide this functionality. Clients which really wish to access the Causes of the underlying errors are free to iterate through the errors themselves.

                                func (MultiError) Error

                                func (m MultiError) Error() string

                                func (MultiError) IsDecode

                                func (m MultiError) IsDecode() bool

                                func (MultiError) IsInternal

                                func (m MultiError) IsInternal() bool

                                func (MultiError) IsUsage

                                func (m MultiError) IsUsage() bool

                                type NopEncoder

                                type NopEncoder struct{}

                                  NopEncoder does not encode cookie values, and instead simply accepts a []byte (as an interface{}) and returns a []byte. This is particularly useful when you encoding an object upstream and do not wish to re-encode it.

                                  func (NopEncoder) Deserialize

                                  func (e NopEncoder) Deserialize(src []byte, dst interface{}) error

                                    Deserialize passes a []byte through as-is.

                                    func (NopEncoder) Serialize

                                    func (e NopEncoder) Serialize(src interface{}) ([]byte, error)

                                      Serialize passes a []byte through as-is.

                                      type SecureCookie

                                      type SecureCookie struct {
                                      	// contains filtered or unexported fields
                                      }

                                        SecureCookie encodes and decodes authenticated and optionally encrypted cookie values.

                                        func New

                                        func New(hashKey, blockKey []byte) *SecureCookie

                                          New returns a new SecureCookie.

                                          hashKey is required, used to authenticate values using HMAC. Create it using GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes.

                                          blockKey is optional, used to encrypt values. Create it using GenerateRandomKey(). The key 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. The default encoder used for cookie serialization is encoding/gob.

                                          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.

                                          func (*SecureCookie) BlockFunc

                                          func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCookie

                                            BlockFunc sets the encryption function used to create a cipher.Block.

                                            Default is crypto/aes.New.

                                            func (*SecureCookie) Decode

                                            func (s *SecureCookie) Decode(name, value string, dst interface{}) error

                                              Decode decodes a cookie value.

                                              It decodes, verifies a message authentication code, optionally decrypts and finally deserializes the value.

                                              The name argument is the cookie name. It must be the same name used when it was stored. The value argument is the encoded cookie value. The dst argument is where the cookie will be decoded. It must be a pointer.

                                              func (*SecureCookie) Encode

                                              func (s *SecureCookie) Encode(name string, value interface{}) (string, error)

                                                Encode encodes a cookie value.

                                                It serializes, optionally encrypts, signs with a message authentication code, and finally encodes the value.

                                                The name argument is the cookie name. It is stored with the encoded value. The value argument is the value to be encoded. It can be any value that can be encoded using the currently selected serializer; see SetSerializer().

                                                It is the client's responsibility to ensure that value, when encoded using the current serialization/encryption settings on s and then base64-encoded, is shorter than the maximum permissible length.

                                                func (*SecureCookie) HashFunc

                                                func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie

                                                  HashFunc sets the hash function used to create HMAC.

                                                  Default is crypto/sha256.New.

                                                  func (*SecureCookie) MaxAge

                                                  func (s *SecureCookie) MaxAge(value int) *SecureCookie

                                                    MaxAge restricts the maximum age, in seconds, for the cookie value.

                                                    Default is 86400 * 30. Set it to 0 for no restriction.

                                                    func (*SecureCookie) MaxLength

                                                    func (s *SecureCookie) MaxLength(value int) *SecureCookie

                                                      MaxLength restricts the maximum length, in bytes, for the cookie value.

                                                      Default is 4096, which is the maximum value accepted by Internet Explorer.

                                                      func (*SecureCookie) MinAge

                                                      func (s *SecureCookie) MinAge(value int) *SecureCookie

                                                        MinAge restricts the minimum age, in seconds, for the cookie value.

                                                        Default is 0 (no restriction).

                                                        func (*SecureCookie) SetSerializer

                                                        func (s *SecureCookie) SetSerializer(sz Serializer) *SecureCookie

                                                          Encoding sets the encoding/serialization method for cookies.

                                                          Default is encoding/gob. To encode special structures using encoding/gob, they must be registered first using gob.Register().

                                                          type Serializer

                                                          type Serializer interface {
                                                          	Serialize(src interface{}) ([]byte, error)
                                                          	Deserialize(src []byte, dst interface{}) error
                                                          }

                                                            Serializer provides an interface for providing custom serializers for cookie values.

                                                            Directories

                                                            Path Synopsis