Skip to content

No CSRF cookie presented with CookieStorage results in 500 Error (not 403 Forbidden) #1

Open
@shuckc

Description

@shuckc

Thanks for this project.
If I use curl to hit a CSRF protected page with a POST request, but without a cookie, the server throws a 500 rather than 403 Forbidden.

% curl -X POST http://localhost:8081/trigger/set-verbose -v
* Connected to localhost (::1) port 8081 (#0)
> POST /trigger/set-verbose HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 500 Internal Server Error
< Content-Type: text/plain; charset=utf-8
< Content-Length: 55
< Date: Thu, 07 Apr 2022 08:53:04 GMT
< Server: Python/3.9 aiohttp/3.8.1
< Connection: close
< 
500 Internal Server Error

* Closing connection 0
Server got itself in trouble

The 500 occurs due to an untrapped exception from the csrf_middleware due to the policy trying to do a constant time comparison with compare_digest between a str and None:

2022-04-07 09:43:34.413 ERROR    Error handling request
Traceback (most recent call last):
  File "/Users/chris/repos/project/venv/lib/python3.9/site-packages/aiohttp/web_protocol.py", line 435, in _handle_request
    resp = await request_handler(request)
  File "/Users/chris/repos/project/venv/lib/python3.9/site-packages/aiohttp/web_app.py", line 504, in _handle
    resp = await handler(request)
  File "/Users/chris/repos/project/venv/lib/python3.9/site-packages/aiohttp/web_middlewares.py", line 117, in impl
    return await handler(request)
  File "/Users/chris/repos/project/web/webapp.py", line 811, in user_auth_middleware
    return await handler(request)
  File "/Users/chris/repos/project/venv/lib/python3.9/site-packages/aiohttp_jinja2/__init__.py", line 264, in context_processors_middleware
    return await handler(request)
  File "/Users/chris/repos/project/venv/lib/python3.9/site-packages/aiohttp_csrf/__init__.py", line 175, in csrf_middleware
    return await handler(request)
  File "/Users/chris/repos/project/venv/lib/python3.9/site-packages/aiohttp_csrf/__init__.py", line 140, in wrapped
    and not await _check(request)
  File "/Users/chris/repos/project/venv/lib/python3.9/site-packages/aiohttp_csrf/__init__.py", line 117, in _check
    return await policy.check(request, original_token)
  File "/Users/chris/repos/project/venv/lib/python3.9/site-packages/aiohttp_csrf/policy.py", line 23, in check
    return compare_digest(token, original_value)
TypeError: unsupported operand types(s) or combination of types: 'str' and 'NoneType'
2022-04-07 09:43:34.419 INFO     ::1 [07/Apr/2022:08:43:34 +0000] "POST /trigger/set-verbose HTTP/1.1" 500 244 "-" "curl/7.64.1"

The aiohttp-csrf setup code looks like:

    app = web.Application(middlewares=middlewares)

    aiohttp_jinja2.setup(
        app,
        loader=jinja2.FileSystemLoader("web/templates"),
        context_processors=[aiohttp_jinja2.request_processor],
    )

    csrf_policy = aiohttp_csrf.policy.FormPolicy("_csrf_token")
    csrf_storage = aiohttp_csrf.storage.CookieStorage(
        "csrf_token", secret_phrase="SECRET"
    )
    aiohttp_csrf.setup(app, policy=csrf_policy, storage=csrf_storage)
    app.middlewares.append(aiohttp_csrf.csrf_middleware)

And requirements.txt includes:

aiohttp==3.7.4.post0
aiohttp-csrf==0.1.1
aiohttp-jinja2==1.4.2
aiohttp-session==2.9.0
aioredis==2.0.0a1

For completeness, the case when the cookie is provided, albeit with a bad value so the comparison fails 'normally':

% curl -X POST http://localhost:8081/trigger/set-verbose --cookie "csrf_token=silly" -v
* Connected to localhost (::1) port 8081 (#0)
> POST /trigger/set-verbose HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.64.1
> Accept: */*
> Cookie: csrf_token=silly
> 
< HTTP/1.1 403 Forbidden
< Content-Type: text/plain; charset=utf-8
< Content-Length: 14
< Date: Thu, 07 Apr 2022 08:56:12 GMT
< Server: Python/3.9 aiohttp/3.8.1
< 
* Connection #0 to host localhost left intact
403: Forbidden
* Closing connection 0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions