For example:
I thought of a couple of potential fixes:
1. Make the debug http response a special class that deletes any CSP
header added to it. This would work for most cases but not if the CSP
header is added outside of Django (WSGI middleware, a server wrapping
runserver).
2. Move the CSS and JS to separate URL's so they're compatible with CSP.
They could be served by a special route/path in `runserver`.
I am personally leaning towards #2 - even though it's more complex, it is
more general.
There's also some opportunity to modernize the CSS and JS in the debug
page a bit, such as rewriting use of window.onload and onclick handlers.
To reproduce, you can save the below as `app.py` and run `python app.py
runserver`:
{{{
import sys
from django.conf import settings
from django.urls import path
settings.configure(
DEBUG=True,
ROOT_URLCONF=__name__,
SECRET_KEY="django-insecure-
r42jn$xf4g+=w@=l#m6ghqo0!$icww-h4+$5gojq(1ld$x%!6f",
MIDDLEWARE=[f"{__name__}.CSPMiddleware"],
)
class CSPMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
response[
"Content-Security-Policy"
] = "object-src 'none'; base-uri 'none'; default-src 'self';"
return response
def index(request):
1 / 0
urlpatterns = [path("", index)]
if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/33180>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* Attachment "error.png" added.
Old description:
New description:
When using a strict CSP header, the debug view is broken as the inline CSS
and JS get blocked by the browser. The page is somewhat usable as all the
text is all visible, but it isn't particularly friendly or necessarily
obvious why it's broken.
For example:
[[Image(https://code.djangoproject.com/attachment/ticket/33180/error.png)]]
{{{
import sys
execute_from_command_line(sys.argv)
}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:1>
Old description:
> When using a strict CSP header, the debug view is broken as the inline
> CSS and JS get blocked by the browser. The page is somewhat usable as all
> the text is all visible, but it isn't particularly friendly or
> necessarily obvious why it's broken.
>
> For example:
>
> [[Image(https://code.djangoproject.com/attachment/ticket/33180/error.png)]]
New description:
When using a strict CSP header, the debug view is broken as the inline CSS
and JS get blocked by the browser. The page is somewhat usable as all the
text is all visible, but it isn't particularly friendly or necessarily
obvious why it's broken.
For example:
[[Image(ticket:33180:error.png)]]
{{{
import sys
execute_from_command_line(sys.argv)
}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:2>
* Attachment "error.png" added.
* Attachment "error.png" removed.
* type: Bug => Cleanup/optimization
* stage: Unreviewed => Accepted
Comment:
Personally, I prefer the second option.
Follow up to #32624.
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:3>
Comment (by Adam Johnson):
One complication is that the HTML email reporter may be used to render
emails. Emails can't use separate CSS. I guess an implementation for #2
may need to pursue a separate CSS file that can be inlined when is_email =
True. (The JS is only used for browser renders.)
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:4>
Comment (by Tom Carrick):
I'm not too sure about a special route for runserver. I'm probably not the
only person that sometimes uses gunicorn/etc. locally or in some other
locked down environment where I still want to see the error pages. I'm not
sure I have a good alternative though.
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:5>
Comment (by Adam Johnson):
It needn't be done by modifying the server per se. It can probably be part
of the WSGI application, which should work under gunicorn etc.
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:6>
Comment (by Teddy Ni):
For convenience, could this be implemented by using [https://content-
security-policy.com/nonce/ a nonce]?
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:7>
Comment (by Adam Johnson):
We could use a nonce with a modified version of my suggested fix #1, since
any CSP header will be added *after* the response has been created. We'd
have to detect the header being added and pull the nonce out of it (if
it's there) or add it, both paths requiring us to parse the header. Sounds
complicated to me.
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:8>
Comment (by Collin Anderson):
I feel like ideally we get `Content-Security-Policy` framework added to
core (#15727) so there's a reliable way to edit CSP headers on a per-
response basis.
Re moving js/css to separate file/url, Google's CSP Evaluator https://csp-
evaluator.withgoogle.com/ (linked from
https://infosec.mozilla.org/guidelines/web_security#content-security-
policy) says regarding `script-src: self`:
"Host whitelists can frequently be bypassed. Consider using 'strict-
dynamic' in combination with CSP nonces or hashes." "'self' can be
problematic if you host JSONP, Angular or user uploaded files."
(There's probably pros and cons either way, as you could still have
injection in an inline-script in a template. `script-src: self` is pretty
popular, and `contrib.admin` relies on it being there.)
--
Ticket URL: <https://code.djangoproject.com/ticket/33180#comment:9>