Secure Cookie

Warning

Deprecated since version 0.15: This will be removed in version 1.0. It has moved tohttps://github.com/pallets/secure-cookie.

werkzeug.contrib.securecookie

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

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

Example usage:

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

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

  1. >>> value = x.serialize()

Loading from that string again:

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

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

Keep in mind that the values will be visible in the cookie so do notstore 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 thesecure cookie into your application like this:

  1. from werkzeug.utils import cached_property
  2. from werkzeug.wrappers import BaseRequest
  3. from werkzeug.contrib.securecookie import SecureCookie
  4.  
  5. # don't use this key but a different one; you could just use
  6. # os.urandom(20) to get something random
  7. SECRET_KEY = '\xfa\xdd\xb8z\xae\xe0}4\x8b\xea'
  8.  
  9. class Request(BaseRequest):
  10.  
  11. @cached_property
  12. def client_session(self):
  13. data = self.cookies.get('session_data')
  14. if not data:
  15. return SecureCookie(secret_key=SECRET_KEY)
  16. return SecureCookie.unserialize(data, SECRET_KEY)
  17.  
  18. def application(environ, start_response):
  19. request = Request(environ)
  20.  
  21. # get a response object here
  22. response = ...
  23.  
  24. if request.client_session.should_save:
  25. session_data = request.client_session.serialize()
  26. response.set_cookie('session_data', session_data,
  27. httponly=True)
  28. return response(environ, start_response)

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

  1. class Request(BaseRequest):
  2.  
  3. @cached_property
  4. def client_session(self):
  5. return SecureCookie.load_cookie(self, secret_key=COOKIE_SECRET)
  6.  
  7. def application(environ, start_response):
  8. request = Request(environ)
  9.  
  10. # get a response object here
  11. response = ...
  12.  
  13. request.client_session.save_cookie(response)
  14. return response(environ, start_response)

Security

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

  1. import json
  2. from werkzeug.contrib.securecookie import SecureCookie
  3.  
  4. class JSONSecureCookie(SecureCookie):
  5. serialization_method = json

The weakness of Pickle is that if someone gains access to the secret keythe attacker can not only modify the session but also execute arbitrarycode 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 providean alternative mac method. The import thing is that the mac methodis a function with a similar interface to the hashlib. Requiredmethods are update() and digest().

Example usage:

  1. >>> x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef")
  2. >>> x["foo"]
  3. 42
  4. >>> x["baz"]
  5. (1, 2, 3)
  6. >>> x["blafasel"] = 23
  7. >>> x.should_save
  8. 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 specifiedit 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 objectsin the cookie:
  1. >>> c = SecureCookie()
  2. >>> c["foo"] = [1, 2, 3]
  3. >>> c.modified
  4. True
  5. >>> c.modified = False
  6. >>> c["foo"].append(4)
  7. >>> c.modified
  8. False

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

  • static hash_method()
  • The hash method to use. This has to be a module with a new functionor 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 arbitraryfunction there such as hashlib.sha1 which might be implementedas a function.

  • classmethod loadcookie(_request, key='session', secret_key=None)

  • Loads a SecureCookie from a cookie in request. If thecookie is not set, a new SecureCookie instanced isreturned.

Parameters:

  1. - **request** a request object that has a _cookies_ attributewhich is a dict of all cookie values.
  2. - **key** the name of the cookie.
  3. - **secret_key** the secret key used to unquote the cookie.Always provide the value even though it hasno default!
  • classmethod quote(value)
  • Quote the value for the cookie. This can be any object supportedby serialization_method.

Parameters:value – the value to quote.

  • quotebase64 = True_
  • if the contents should be base64 quoted. This can be disabled if theserialization process returns cookie safe strings only.

  • savecookie(_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. Allparameters that are not described here are forwarded directlyto set_cookie().

Parameters:

  1. - **response** a response object that has a<code>set_cookie()</code> method.
  2. - **key** the name of the cookie.
  3. - **session_expires** the expiration date of the secure cookiestored information. If this is not providedthe cookie _expires_ date is used instead.
  • serializationmethod = _
  • The module used for serialization. Should have a dumps and aloads method that takes bytes. The default is pickle.

Changed in version 0.15: The default of pickle will change to json in 1.0.

  • serialize(expires=None)
  • Serialize the secure cookie into a string.

If expires is provided, the session will be automatically invalidatedafter expiration when you unseralize it. This provides betterprotection against session cookie theft.

Parameters:expires – an optional expiration date for the cookie (adatetime.datetime object)

  • should_save
  • True if the session should be saved. By default this is only truefor modified cookies, not new.

  • classmethod unquote(value)

  • Unquote the value for the cookie. If unquoting does not work aUnquoteError is raised.

Parameters:value – the value to unquote.

  • classmethod unserialize(string, secret_key)
  • Load the secure cookie from a serialized string.

Parameters:

  1. - **string** the cookie value to unserialize.
  2. - **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.