Skip to content

Commit 9016e7d

Browse files
tardypasvetlov
authored andcommitted
Fix NaClCookieStorage for corrupt cookie generating error 500 (#317)
* NaClCookieStorage: manage corrupt cookies * fix doc for NaClCookieStorage
1 parent cecdc72 commit 9016e7d

File tree

3 files changed

+53
-7
lines changed

3 files changed

+53
-7
lines changed

aiohttp_session/nacl_storage.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import binascii
12
import json
23

34
import nacl.secret
45
import nacl.utils
6+
import nacl.exceptions
57
from nacl.encoding import Base64Encoder
68

79
from . import AbstractStorage, Session
10+
from .log import log
811

912

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

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

28+
def empty_session(self):
29+
return Session(None, data=None, new=True, max_age=self.max_age)
30+
2531
async def load_session(self, request):
2632
cookie = self.load_cookie(request)
2733
if cookie is None:
28-
return Session(None, data=None, new=True, max_age=self.max_age)
34+
return self.empty_session()
2935
else:
30-
data = self._decoder(
31-
self._secretbox.decrypt(cookie.encode('utf-8'),
32-
encoder=Base64Encoder).decode('utf-8')
33-
)
34-
return Session(None, data=data, new=False, max_age=self.max_age)
36+
try:
37+
data = self._decoder(
38+
self._secretbox.decrypt(
39+
cookie.encode('utf-8'),
40+
encoder=Base64Encoder).decode('utf-8')
41+
)
42+
return Session(None, data=data, new=False,
43+
max_age=self.max_age)
44+
except (binascii.Error, nacl.exceptions.CryptoError):
45+
log.warning("Cannot decrypt cookie value, "
46+
"create a new fresh session")
47+
return self.empty_session()
3548

3649
async def save_session(self, request, response, session):
3750
if session.empty:

docs/reference.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ To use the storage you should push it into
348348
:func:`~aiohttp_session.session_middleware`::
349349

350350
app = aiohttp.web.Application(middlewares=[
351-
aiohttp_session.cookie_storage.NaClCookieStorage(
351+
aiohttp_session.nacl_storage.NaClCookieStorage(
352352
b'Thirty two length bytes key.'])
353353

354354
.. class:: NaClCookieStorage(secret_key, *, \

tests/test_nacl_storage.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,36 @@ async def handler(request):
179179

180180
resp = await client.get('/?exp=yes')
181181
assert resp.status == 200
182+
183+
184+
async def test_load_corrupted_session(aiohttp_client, key):
185+
186+
async def handler(request):
187+
session = await get_session(request)
188+
assert isinstance(session, Session)
189+
assert session.new
190+
assert {} == session
191+
return web.Response(body=b'OK')
192+
193+
client = await aiohttp_client(create_app(handler, key))
194+
client.session.cookie_jar.update_cookies({'AIOHTTP_SESSION': 'bad key'})
195+
resp = await client.get('/')
196+
assert resp.status == 200
197+
198+
199+
async def test_load_session_different_key(aiohttp_client, key):
200+
201+
async def handler(request):
202+
session = await get_session(request)
203+
assert isinstance(session, Session)
204+
assert session.new
205+
assert {} == session
206+
return web.Response(body=b'OK')
207+
208+
client = await aiohttp_client(create_app(handler, key))
209+
# create another box with another key
210+
key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)
211+
secretbox = nacl.secret.SecretBox(key)
212+
make_cookie(client, secretbox, {'a': 1, 'b': 12})
213+
resp = await client.get('/')
214+
assert resp.status == 200

0 commit comments

Comments
 (0)