Open
Description
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
Labels
No labels