Secure Cookie — Werkzeug 0.12.1 documentation

# Secure Cookie

This module implements a cookie that is not alterable from the client because it adds a checksum the server checks for. You can use it as session replacement if all you have is a user id or something to mark a logged in user.

Keep in mind that the data is still readable from the client as a normal cookie is. However you don’t have to store and flush the sessions you have at the server.

Example usage:

    >>> from werkzeug.contrib.securecookie import SecureCookie
    >>> x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef")

Dumping into a string so that one can store it in a cookie:

    >>> value = x.serialize()

Loading from that string again:

    >>> x = SecureCookie.unserialize(value, "deadbeef")
    >>> x["baz"]
    (1, 2, 3)

If someone modifies the cookie and the checksum is wrong the unserialize method will fail silently and return a new empty SecureCookie object.

Keep in mind that the values will be visible in the cookie so do not store data in a cookie you don’t want the user to see.

## Application Integration

If you are using the werkzeug request objects you could integrate the secure cookie into your application like this:

    from werkzeug.utils import cached_property
    from werkzeug.wrappers import BaseRequest
    from werkzeug.contrib.securecookie import SecureCookie

    # don't use this key but a different one; you could just use
    # os.urandom(20) to get something random
    SECRET_KEY = '\xfa\xdd\xb8z\xae\xe0}4\x8b\xea'

    class Request(BaseRequest):

        @cached_property
        def client_session(self):
            data = self.cookies.get('session_data')
            if not data:
                return SecureCookie(secret_key=SECRET_KEY)
            return SecureCookie.unserialize(data, SECRET_KEY)

    def application(environ, start_response):
        request = Request(environ)

        # get a response object here
        response = ...

        if request.client_session.should_save:
            session_data = request.client_session.serialize()
            response.set_cookie('session_data', session_data,
                                httponly=True)
        return response(environ, start_response)

A less verbose integration can be achieved by using shorthand methods:

    class Request(BaseRequest):

        @cached_property
        def client_session(self):
            return SecureCookie.load_cookie(self, secret_key=COOKIE_SECRET)

    def application(environ, start_response):
        request = Request(environ)

        # get a response object here
        response = ...

        request.client_session.save_cookie(response)
        return response(environ, start_response)

## Security

The default implementation uses Pickle as this is the only module that used to be available in the standard library when this module was created. If you have simplejson available it’s strongly recommended to create a subclass and replace the serialization method:

    import json
    from werkzeug.contrib.securecookie import SecureCookie

    class JSONSecureCookie(SecureCookie):
        serialization_method = json

The weakness of Pickle is that if someone gains access to the secret key the attacker can not only modify the session but also execute arbitrary code on the server.

## Reference

class `werkzeug.contrib.securecookie.` `SecureCookie`(data=None, secret_key=None, new=True)

  Represents a secure cookie. You can subclass this class and provide an alternative mac method. The import thing is that the mac method is a function with a similar interface to the hashlib. Required methods are update() and digest().

  Example usage:

      >>> x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef")
      >>> x["foo"]
      42
      >>> x["baz"]
      (1, 2, 3)
      >>> x["blafasel"] = 23
      >>> x.should_save
      True

  Parameters

    - data – the initial data. Either a dict, list of tuples or None.

    - secret_key – the secret key. If not set None or not specified it has to be set before `serialize()` is called.

    - new – The initial value of the new flag.

  `new`

    True if the cookie was newly created, otherwise False

  `modified`

    Whenever an item on the cookie is set, this attribute is set to True. However this does not track modifications inside mutable objects in the cookie:

        >>> c = SecureCookie()
        >>> c["foo"] = [1, 2, 3]
        >>> c.modified
        True
        >>> c.modified = False
        >>> c["foo"].append(4)
        >>> c.modified
        False

    In that situation it has to be set to modified by hand so that `should_save` can pick it up.

  static `hash_method`(string=b'')

    The hash method to use. This has to be a module with a new function or a function that creates a hashlib object. Such as hashlib.md5 Subclasses can override this attribute. The default hash is sha1. Make sure to wrap this in staticmethod() if you store an arbitrary function there such as hashlib.sha1 which might be implemented as a function.

  classmethod `load_cookie`(request, key='session', secret_key=None)

    Loads a `SecureCookie` from a cookie in request. If the cookie is not set, a new `SecureCookie` instanced is returned.

    Parameters

      - request – a request object that has a cookies attribute which is a dict of all cookie values.

      - key – the name of the cookie.

      - secret_key – the secret key used to unquote the cookie. Always provide the value even though it has no default!

  classmethod `quote`(value)

    Quote the value for the cookie. This can be any object supported by `serialization_method`.

    Parameters

      value – the value to quote.

  `quote_base64` = True

    if the contents should be base64 quoted. This can be disabled if the serialization process returns cookie safe strings only.

  `save_cookie`(response, key='session', expires=None, session_expires=None, max_age=None, path='/', domain=None, secure=None, httponly=False, force=False)

    Saves the SecureCookie in a cookie on response object. All parameters that are not described here are forwarded directly to `set_cookie()`.

    Parameters

      - response – a response object that has a `set_cookie()` method.

      - key – the name of the cookie.

      - session_expires – the expiration date of the secure cookie stored information. If this is not provided the cookie expires date is used instead.

  `serialization_method` = <module 'pickle' from '/usr/local/lib/python3.8/pickle.py'>

    the module used for serialization. Unless overriden by subclasses the standard pickle module is used.

  `serialize`(expires=None)

    Serialize the secure cookie into a string.

    If expires is provided, the session will be automatically invalidated after expiration when you unseralize it. This provides better protection against session cookie theft.

    Parameters

      expires – an optional expiration date for the cookie (a `datetime.datetime` object)

  property `should_save`

    True if the session should be saved. By default this is only true for `modified` cookies, not `new`.

  classmethod `unquote`(value)

    Unquote the value for the cookie. If unquoting does not work a `UnquoteError` is raised.

    Parameters

      value – the value to unquote.

  classmethod `unserialize`(string, secret_key)

    Load the secure cookie from a serialized string.

    Parameters

      - string – the cookie value to unserialize.

      - secret_key – the secret key used to serialize the cookie.

    Returns

      a new `SecureCookie`.

exception `werkzeug.contrib.securecookie.` `UnquoteError`

  Internal exception used to signal failures on quoting.