Skip to content

CookieError on invalid cookie names #2683

@irmatov

Description

@irmatov

Long story short

aiohttp servers fail with 500 Internal error on requests where Cookie header is present and cookie name contains invalid symbols for cookie name. aiohttp uses SimpleCookie from python's http.cookies package. Although SimpleCookie follows standards and supposedly correctly rejects such cookie names, real world is much messier and such cookies are seen frequently.

For the reference, RFC2109 states that cookie attribute (name) is a token:

The two state management headers, Set-Cookie and Cookie, have common
syntactic properties involving attribute-value pairs.  The following
grammar uses the notation, and tokens DIGIT (decimal digits) and
token (informally, a sequence of non-special, non-white space
characters) from the HTTP/1.1 specification [RFC 2068] to describe
their syntax.

av-pairs        =       av-pair *(";" av-pair)
av-pair         =       attr ["=" value]        ; optional value
attr            =       token

RFC2616 defines token as:

token          = 1*<any CHAR except CTLs or separators>
separators     = "(" | ")" | "<" | ">" | "@"
               | "," | ";" | ":" | "\" | <">
               | "/" | "[" | "]" | "?" | "="
               | "{" | "}" | SP | HT

So any cookie attribute containing one of ( ) < > @ , ; : \ " / [ ] ? = { } SP HT is considered invalid by SimpleCookie. Django uses own cookie parsing because of similar reasons.

Expected behaviour

Such invalid cookie should still be accepted as they are tolerated by browsers and most web servers.

Actual behaviour

500 Internal server error caused by exception CookieError.

Steps to reproduce

Given sample http server:

from aiohttp import web

async def handle(request):
    text = ""
    for k, v in request.cookies:
        text += '\n{}\t{}'.format(k, v)
    return web.Response(text=text)

app = web.Application()
app.router.add_get('/', handle)
app.router.add_get('/{name}', handle)

web.run_app(app)

When one executes curl -H 'Cookie: ISAWPLB{DB45DF86-F806-407C-932C-D52A60E4019E}=x' -v http://localhost:8080/ against this server it receives 500 internal server error. On the server side a traceback is visible:

Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/aiohttp/helpers.py", line 554, in __get__
    return inst._cache[self.name]
KeyError: 'cookies'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/aiohttp/web_protocol.py", line 410, in start
    resp = yield from self._request_handler(request)
  File "/usr/local/lib/python3.5/dist-packages/aiohttp/web.py", line 325, in _handle
    resp = yield from handler(request)
  File "/usr/local/lib/python3.5/dist-packages/aiohttp/web_middlewares.py", line 93, in impl
    return (yield from handler(request))
  File "./test.py", line 7, in handle
    for k, v in request.cookies:
  File "/usr/local/lib/python3.5/dist-packages/aiohttp/helpers.py", line 556, in __get__
    val = self.wrapped(inst)
  File "/usr/local/lib/python3.5/dist-packages/aiohttp/web_request.py", line 413, in cookies
    parsed = SimpleCookie(raw)
  File "/usr/lib/python3.5/http/cookies.py", line 507, in __init__
    self.load(input)
  File "/usr/lib/python3.5/http/cookies.py", line 556, in load
    self.__parse_string(rawdata)
  File "/usr/lib/python3.5/http/cookies.py", line 620, in __parse_string
    self.__set(key, rval, cval)
  File "/usr/lib/python3.5/http/cookies.py", line 512, in __set
    M.set(key, real_value, coded_value)
  File "/usr/lib/python3.5/http/cookies.py", line 380, in set
    raise CookieError('Illegal key %r' % (key,))
http.cookies.CookieError: Illegal key 'ISAWPLB{DB45DF86-F806-407C-932C-D52A60E4019E}'

Your environment

Tested on Ubuntu 16.04, aiohttp version 2.3.9 installed through pip.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions