summaryrefslogtreecommitdiffstats
path: root/accounts/utils/sessions.py
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2016-01-24 03:55:49 +0100
committerAlexander Sulfrian <alexander@sulfrian.net>2016-02-02 04:22:16 +0100
commit5e7e7fc832d26178a6036ed483fe3cfffe2b22b2 (patch)
treec74302270b7c262d744876f1d2f93bc84c44a2ba /accounts/utils/sessions.py
parent6eb1db6bff15e1611767f5219ee1b4ea558e3d28 (diff)
downloadweb-5e7e7fc832d26178a6036ed483fe3cfffe2b22b2.tar.gz
web-5e7e7fc832d26178a6036ed483fe3cfffe2b22b2.tar.bz2
web-5e7e7fc832d26178a6036ed483fe3cfffe2b22b2.zip
Encrypt the session data by default
Before we just encrypted the password, now we encrypt the whole session information by default.
Diffstat (limited to 'accounts/utils/sessions.py')
-rw-r--r--accounts/utils/sessions.py62
1 files changed, 62 insertions, 0 deletions
diff --git a/accounts/utils/sessions.py b/accounts/utils/sessions.py
new file mode 100644
index 0000000..cd12030
--- /dev/null
+++ b/accounts/utils/sessions.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+from Crypto import Random
+from Crypto.Cipher import AES
+from flask import current_app
+from flask.sessions import TaggedJSONSerializer, SecureCookieSessionInterface
+from itsdangerous import BadPayload
+
+
+def _pad(value, block_size):
+ padding = block_size - len(value) % block_size
+ return value + (padding * chr(padding))
+
+
+def _unpad(value):
+ pad_length = ord(value[len(value)-1:])
+ return value[:-pad_length]
+
+
+class EncryptedSerializer(TaggedJSONSerializer):
+
+ def __init__(self):
+ self.block_size = AES.block_size
+
+ def _cipher(self, iv):
+ return AES.new(
+ current_app.config['SESSION_ENCRYPTION_KEY'],
+ AES.MODE_CBC, iv)
+
+ def dumps(self, value):
+ """
+ Encrypt the serialized values with `config.SESSION_ENCRYPTION_KEY`.
+ The key must be 32 bytes long.
+ """
+ assert len(current_app.config['SESSION_ENCRYPTION_KEY']) == 32
+
+ serialized_value = super(EncryptedSerializer, self).dumps(value)
+
+ raw = _pad(serialized_value, self.block_size)
+ iv = Random.new().read(self.block_size)
+ return iv + self._cipher(iv).encrypt(raw)
+
+ def loads(self, value):
+ """
+ Decrypt the given serialized session data with
+ `config.SESSION_ENCRYPTION_KEY`.
+ """
+ iv = value[:self.block_size]
+ raw = self._cipher(iv).decrypt(value[AES.block_size:])
+ return super(EncryptedSerializer, self).loads(_unpad(raw))
+
+
+class EncryptedSessionInterface(SecureCookieSessionInterface):
+ serializer = EncryptedSerializer()
+
+ def open_session(self, *args, **kwargs):
+ try:
+ parent = super(EncryptedSessionInterface, self)
+ return parent.open_session(*args, **kwargs)
+ except BadPayload:
+ return self.session_class()