Metadata-Version: 2.1
Name: asgi-csrf
Version: 0.5.1
Summary: ASGI middleware for protecting against CSRF attacks
Home-page: https://github.com/simonw/asgi-csrf
Author: Simon Willison
License: Apache License, Version 2.0
Platform: UNKNOWN
Description-Content-Type: text/markdown
Requires-Dist: itsdangerous
Provides-Extra: test
Requires-Dist: pytest ; extra == 'test'
Requires-Dist: pytest-asyncio ; extra == 'test'
Requires-Dist: httpx ; extra == 'test'
Requires-Dist: starlette ; extra == 'test'
Requires-Dist: python-multipart ; extra == 'test'

# asgi-csrf

[![PyPI](https://img.shields.io/pypi/v/asgi-csrf.svg)](https://pypi.org/project/asgi-csrf/)
[![CircleCI](https://circleci.com/gh/simonw/asgi-csrf.svg?style=svg)](https://circleci.com/gh/simonw/asgi-csrf)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/simonw/asgi-csrf/blob/master/LICENSE)

ASGI middleware for protecting against CSRF attacks

## Installation

    pip install asgi-csrf

## Background

See the [OWASP guide to Cross Site Request Forgery (CSRF)](https://owasp.org/www-community/attacks/csrf) and their [Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html).

This middleware implements the [Double Submit Cookie pattern](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie), where a cookie is set that is then compared to a `csrftoken` hidden form field or a `x-csrftoken` HTTP header.

## Usage

Decorate your ASGI application like this:

```python
from asgi_csrf import asgi_csrf
from .my_asgi_app import app


app = asgi_csrf(app, signing_secret="secret-goes-here")
```

The middleware will set a `csrftoken` cookie, if one is missing. The value of that token will be made available to your ASGI application through the `scope["csrftoken"]` function.

Your application code should include that value as a hidden form field in any POST forms:

```html
<form action="/login" method="POST">
    ...
    <input type="hidden" name="csrftoken" value="{{ request.scope.csrftoken() }}">
</form>
```

Note that `request.scope["csrftoken"]` is a function that returns a string. Calling that function also lets the middleware know that the cookie should be set by that page, if the user does not already have that cookie.

If the cookie needs to be set, the middleware will add a `Vary: Cookie` header to the response to ensure it is not incorrectly cached by any CDNs or intermediary proxies.

The middleware will return a 403 forbidden error for any POST requests that do not include the matching `csrftoken` - either in the POST data or in a `x-csrftoken` HTTP header (useful for JavaScript `fetch()` calls).

The `signing_secret` is used to sign the tokens, to protect against subdomain vulnerabilities.

If you do not pass in an explicit `signing_secret` parameter, the middleware will look for a `ASGI_CSRF_SECRET` environment variable.

If it cannot find that environment variable, it will generate a random secret which will persist for the lifetime of the server.

This means that if you do not configure a specific secret your user's `csrftoken` cookies will become invalid every time the server restarts! You should configure a secret.

## Limitations

* Currently only works for `application/x-www-form-urlencoded` forms, not `multipart/form-data` forms (with file uploads)


