# Verbose CSRF Middleware

This is a verbatim copy of the Django CSRF middleware, but it is more verbose in its failures.

This is especially useful when CSRF failures are happening due to some misconfiguration of your server, your reverse
proxy, or some combination thereof.

Django 4.2 introduced various "more strict" CSRF checks, in particular checks on the `Origin` and `Referer` header.
This middleware can help you debug problems with those checks in your setup.

### Usage:

In your `settings.py` file, in the `MIDDLEWARE_CLASSES`, search for this line:

```
    'django.middleware.csrf.CsrfViewMiddleware',  # search this to remove it
```

and then _replace_ it with the line below:

```
    'verbose_csrf_middleware.CsrfViewMiddleware',
```

### Seeing the output

You'll probably want to see the output of the middleware _somewhere_. You can either:

1. Turn on `DEBUG`
2. Make sure messages to the logger `"django.security.csrf"` (level: warning) end up in a location you can read.
3. Add a template `403_csrf.html` to your templates directory. Make sure the template renders `"reason"`.
4. Add a [`CSRF_FAILURE_VIEW`](https://docs.djangoproject.com/en/dev/ref/settings/#csrf-failure-view)

Note that optinos 1, 3 and 4 have at least theoretical security implications, because by the nature of "verbose" they
expose some information to end-users.

### Why is this better?

Compare the below; `-` is Django's standard message, `+` is the verbose one. You'll see the latter contains much more
useful info.

```
- Origin checking failed - http://nonmatching does not match any trusted origins.
+ Origin header does not match (deduced) Host: 'http://nonmatching' != 'http://testserver'

- Origin checking failed - https://thisiswrong.example.org does not match any trusted origins.
+ Origin header does not match (deduced) Host: 'https://thisiswrong.example.org' != 'https://testserver'; nor any of the CSRF_TRUSTED_ORIGINS: ['https://subdomain.example.org']

- Origin checking failed - https://anything.example.org does not match any trusted origins.
+ Origin header does not match (deduced) Host: 'https://anything.example.org' != 'https://testserver'; nor any of the CSRF_TRUSTED_ORIGINS: ['http://*.example.org (wrong scheme)']

- Origin checking failed - null does not match any trusted origins.
+ Origin header does not match (deduced) Host: 'null' != 'http://testserver'

- Referer checking failed - https://refererheader.org/ does not match any trusted origins.
+ Referer checking failed - 'refererheader.org' does not match any of ['csrf_trusted_origin.org', 'testserver'].

- Referer checking failed - https://www.wrong.org/ does not match any trusted origins.
+ Referer checking failed - 'www.wrong.org' does not match any of ['testserver'].

- Referer checking failed - https://nonmatching.example.org/ does not match any trusted origins.
+ Referer checking failed - 'nonmatching.example.org' does not match any of ['expected.example.org'].
```

(this output is generated by running the test suite, but turning on Django's standard middleware)

### Compatability

This middleware is a verbatim copy of Django 4.2's csrf middleware, with changes for verbosity.
There were no (meaningful) changes between Django 4.2 and Django 5.1 to that code.
So the middleware is compatible with Django 4.2, Django 5.0 and Django 5.2.


