Skip to content

Commit

Permalink
Fix NaClCookieStorage for corrupt cookie generating error 500 (#317)
Browse files Browse the repository at this point in the history
* NaClCookieStorage: manage corrupt cookies

* fix doc for NaClCookieStorage
  • Loading branch information
tardyp authored and asvetlov committed Sep 12, 2018
1 parent cecdc72 commit 9016e7d
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 7 deletions.
25 changes: 19 additions & 6 deletions aiohttp_session/nacl_storage.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import binascii
import json

import nacl.secret
import nacl.utils
import nacl.exceptions
from nacl.encoding import Base64Encoder

from . import AbstractStorage, Session
from .log import log


class NaClCookieStorage(AbstractStorage):
Expand All @@ -22,16 +25,26 @@ def __init__(self, secret_key, *, cookie_name="AIOHTTP_SESSION",

self._secretbox = nacl.secret.SecretBox(secret_key)

def empty_session(self):
return Session(None, data=None, new=True, max_age=self.max_age)

async def load_session(self, request):
cookie = self.load_cookie(request)
if cookie is None:
return Session(None, data=None, new=True, max_age=self.max_age)
return self.empty_session()
else:
data = self._decoder(
self._secretbox.decrypt(cookie.encode('utf-8'),
encoder=Base64Encoder).decode('utf-8')
)
return Session(None, data=data, new=False, max_age=self.max_age)
try:
data = self._decoder(
self._secretbox.decrypt(
cookie.encode('utf-8'),
encoder=Base64Encoder).decode('utf-8')
)
return Session(None, data=data, new=False,
max_age=self.max_age)
except (binascii.Error, nacl.exceptions.CryptoError):
log.warning("Cannot decrypt cookie value, "
"create a new fresh session")
return self.empty_session()

async def save_session(self, request, response, session):
if session.empty:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ To use the storage you should push it into
:func:`~aiohttp_session.session_middleware`::

app = aiohttp.web.Application(middlewares=[
aiohttp_session.cookie_storage.NaClCookieStorage(
aiohttp_session.nacl_storage.NaClCookieStorage(
b'Thirty two length bytes key.'])

.. class:: NaClCookieStorage(secret_key, *, \
Expand Down
33 changes: 33 additions & 0 deletions tests/test_nacl_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,36 @@ async def handler(request):

resp = await client.get('/?exp=yes')
assert resp.status == 200


async def test_load_corrupted_session(aiohttp_client, key):

async def handler(request):
session = await get_session(request)
assert isinstance(session, Session)
assert session.new
assert {} == session
return web.Response(body=b'OK')

client = await aiohttp_client(create_app(handler, key))
client.session.cookie_jar.update_cookies({'AIOHTTP_SESSION': 'bad key'})
resp = await client.get('/')
assert resp.status == 200


async def test_load_session_different_key(aiohttp_client, key):

async def handler(request):
session = await get_session(request)
assert isinstance(session, Session)
assert session.new
assert {} == session
return web.Response(body=b'OK')

client = await aiohttp_client(create_app(handler, key))
# create another box with another key
key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)
secretbox = nacl.secret.SecretBox(key)
make_cookie(client, secretbox, {'a': 1, 'b': 12})
resp = await client.get('/')
assert resp.status == 200

0 comments on commit 9016e7d

Please sign in to comment.