Secure Cookies¶
A signed cookie that is not alterable from the client because it adds a checksum that the server validates. If you don’t store a lot of data in the session, you can use a secure cookie and not need to set up storage on the server.
Keep in mind that the data is still readable from the client, only not writable. It is signed, not encrypted. Do not store data in a cookie you don’t want the user to see.
from secure_cookie.cookie 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")
assert 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.
Application Integration¶
If you are using the Werkzeug Request
object you could integrate a
secure cookie into your application like this:
from secure_cookie.cookie import SecureCookie
from werkzeug.utils import cached_property
from werkzeug.wrappers import Response
from werkzeug.wrappers import Request
# Don't use this key but a different one; you could use
# os.urandom(16) to get some random bytes.
SECRET_KEY = b"úݸz®à}4ê"
class SessionRequest(Request):
@cached_property
def session(self):
data = self.cookies.get("session")
if not data:
return SecureCookie(secret_key=SECRET_KEY)
return SecureCookie.unserialize(data, SECRET_KEY)
@SessionRequest.application
def application(request):
response = Response(do_stuff(request))
if request.client_session.should_save:
response.set_cookie(
key="session",
value=request.client_session.serialize(),
httponly=True,
)
return response
A less verbose integration can be achieved by using shorthand methods:
class SessionRequest(Request):
@cached_property
def session(self):
return SecureCookie.load_cookie(self, secret_key=COOKIE_SECRET)
@SessionRequest.application
def application(request):
response = Response(do_stuff(request))
request.client_session.save_cookie(response)
return response
API¶
- class secure_cookie.cookie.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()
anddigest()
.x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef") assert x["foo"] == 42 assert x["baz"] == (1, 2, 3) x["blafasel"] = 23 assert x.should_save is True
- Parameters
data – The initial data. Either a dict, list of tuples, or
None
.secret_key – The secret key. If
None
or not specified it has to be set beforeserialize()
is called.new – The initial value of the
new
flag.
Changed in version 0.1.0: The default serialization method is
json
instead ofpickle
. To upgrade existing tokens, override unquote to trypickle
ifjson
fails.- static hash_method()¶
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 func: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 ashashlib.sha1()
which might be implemented as a function.
- classmethod load_cookie(request, key='session', secret_key=None)¶
Load a
SecureCookie
from a cookie in the request. If the cookie is not set, a newSecureCookie
instance 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)¶
Save the data securely 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¶
The module used for serialization. Should have a
dumps
and aloads
method that takes bytes. The default isjson
.Changed in version 0.1.0: Use
json
instead ofpickle
.alias of
_JSONModule
- serialize(expires=None)¶
Serialize the secure cookie into a string.
If expires is provided, the session will be automatically invalidated after expiration when you unserialize 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, notnew
.
- 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 secure_cookie.cookie.UnquoteError¶
Internal exception used to signal failures on quoting.