* stage: Someday/Maybe => Accepted
Comment:
Now that CSP is much closer to being finalized, I would personally like to
see this as part of Django core. We already protect against XSS, CSRF, and
clickjacking; CSP fits right in with these features.
The work which can be done now (before the spec is finalized) mainly
involves removing inline scripting and the mixing of styling and markup in
the HTML templates we ship. This makes sense from the perspectives of both
security and best practices. This would be a really good task for a group
people to tackle during a sprint. Once the spec is finalized, we can work
to integrate django-csp more closely, to the point that it makes sense to
pull into core.
Even if we can't spend the time to really lock down the admin (and we may
not, given our stance that the admin tends to be for trusted users), I
think it makes sense to ship a CSP implementation with Django, so that
projects can use a canonical, well tested, carefully implemented solution.
Security features are hard to get right, and it makes sense to bless one
and concentrate effort, rather than waiting to see which one wins.
The current spec can be found here: http://www.w3.org/TR/CSP/
I'm moving this back into accepted, with the caveat that it won't land in
the near future (1.6 timeframe is probably realistic).
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:9>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* cc: eromijn@… (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:10>
Comment (by nhazar):
After 3 years and 5 major releases, adding content security policy support
to Django would still totally rock.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:11>
* status: new => assigned
* owner: nobody => Rudolph
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:12>
* has_patch: 0 => 1
* version: 1.2 => master
Comment:
Pull request has been added with tests and documentation.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:13>
* needs_docs: 0 => 1
Comment:
Thanks for that patch. In general, I think it is important that we
document well how to change projects to be CSP-compatible. The easier we
make this, the more projects will use CSP, the safer people will be. A few
quick notes:
* I agree with PaulM that we could accept having the admin not CSP-
compatible. However, we should very clearly document that CSP currently
breaks with the admin. If I remember correctly, mozilla's django-csp
allows one to add excluded paths, so that one can have both CSP and the
admin enabled. That does reduce effectiveness, of course, but is better
than no CSP.
* With in-line javascript no longer allowed, it would be useful to point
out `<script type="application/json"></script>` to people, which if my
memory serves me right makes it easy to include a bit of json in your
templates without violating CSP. Not 100% sure here though.
* That can also help for the `{% url %}` problem described in comment:2,
but perhaps there are other suggestions we can make.
* This also deserves a place in the 1.8 release notes and in the security
documentation (we have a specific page for that).
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:14>
Comment (by Rudolph):
Thanks for your comment.
Current pull request does not enable a Content-Security-Policy by default,
because we can make no assumptions about the implementation details of
other people's code. So the admin will stay fully functional unless you
specify a policy which is too strict for the admin. However I agree that
it would be nice to also provide a default policy for the admin (as strict
as currently possible), which should be configurable for people that want
to allow more (i.e. load external scripts).
Comment:2 can be easily solved by putting url's and other data needed by
Javascript in data attributes instead.
I'll add something to the release notes in my update to the pull request.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:15>
Comment (by carljm):
For reference, the PR is at https://github.com/django/django/pull/3550
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:16>
Comment (by carljm):
The code looks reasonable to me. I agree with all of @erikr's
recommendations regarding additional documentation.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:17>
Comment (by gavinwahl):
I don't see any value in adding the ability for django to set the CSP
header for you. I can easily do that myself with a middleware.
The important thing for django to support is to make the admin compatible
with CSP. Otherwise, most installations can't use CSP anyway.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:18>
Comment (by timgraham):
The work to remove inline JavaScript in the admin is tracked in #25165.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:19>
Comment (by Tim Graham <timograham@…>):
In [changeset:"d638cdc42acec608c1967f44af6be32a477c239f" d638cdc]:
{{{
#!CommitTicketReference repository=""
revision="d638cdc42acec608c1967f44af6be32a477c239f"
Fixed #25165 -- Removed inline JavaScript from the admin.
This allows setting a Content-Security-Policy HTTP header
(refs #15727).
Special thanks to blighj, the original author of this patch.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:20>
Comment (by graingert):
patch available at https://github.com/django/django/pull/5776
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:21>
Comment (by timgraham):
Consensus from [https://groups.google.com/d/topic/django-
developers/OITfIvTOp0A/discussion django-developers] is to add this to
`SecurityMiddleware`.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:22>
* cc: emorley@… (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:23>
Comment (by Vlastimil Zíma):
If the `django-csp` should be included in Django. I suggest to modify it
to allow enforcing and monitoring mode alongside, as noted in CSP
specification itself. One set of rules may be enforced and different set
of rules may be reported.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:24>
* owner: Rudolph Froger => Tom Forbes
* cc: Tom Forbes (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:25>
Comment (by Sebastien Dubois):
Any news about this feature request?
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:26>
Comment (by Dylan Young):
FYI I've started work on multi policy support in django-csp. Once that's
completed, it should be easy to fold into core.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:27>
Comment (by Collin Anderson):
https://github.com/mozilla/django-csp/issues/135 is the tracking ticket
for merging on the `django-csp` side of things. Sounds like we want to
have support for `Report-Only` / multiple policies before merging.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:28>
Comment (by Dylan Young):
One potential snag here is that I don't think Django can currently support
multiple of the same header currently (aside from Set-Cookie), unless
there's some API I'm missing...
Is this something there's interest in adding to core? It looks like the
python native wsgiref supports this as well:
https://docs.python.org/3/library/wsgiref.html?highlight=headers%20multi%20value
#module-wsgiref.headers.
See here:
https://github.com/w3c/webappsec-
csp/issues/215#:~:text=A%20server%20MUST%20NOT%20send,resource%20or%20with%20different%20resources.
I don't think it's critical, but it'd be nice as it's standards compliant
behaviour.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:29>
* owner: Tom Forbes => Anvesh Mishra
Comment:
I have summarized the state of play so far
[https://forum.djangoproject.com/t/gsoc-2023-discussion-on-security-bring-
cors-and-csp-into-core/18932 here] and will be working on this ticket.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:30>
Comment (by Claude Paroz):
Also note #25706 (CSP for GIS admin) is still open and is a non-trivial
issue.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:31>
* cc: Petr Přikryl (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:32>
Comment (by Anvesh Mishra):
Had some implementation ideas needed suggestions:
CSP should be added to the SecurityMiddleware according to Tim Graham's
[https://code.djangoproject.com/ticket/15727 comment], so some of the
implementation ideas that I wanted to share are:
1) The following settings will have to be added to
`conf\global_settings.py`:
{{{#!py
SECURE_CSP = {}
SECURE_CSP_INCLUDE_NONCE_IN = None
SECURE_CSP_REPORT_ONLY = {}
SECURE_CSP_EXCLUDE_URL_PREFIXES = ()
}}}
2) Implementation for CSP and Report-Only with nonce support in
SecurityMiddleware:
{{{#!py
class SecurityMiddleware(MiddlewareMixin):
def __init__(self, get_response):
super().__init__(get_response)
self.csp = settings.SECURE_CSP
self.csp_report_only = settings.SECURE_CSP_REPORT_ONLY
self.csp_nonce = settings.SECURE_CSP_INCLUDE_NONCE_IN
def _make_nonce(self, request):
if not getattr(request, '_csp_nonce', None):
request._csp_nonce = (
base64
.b64encode(os.urandom(16))
.decode("ascii")
)
return request._csp_nonce
def process_request(self, request):
path = request.path.lstrip("/")
nonce = partial(self._make_nonce, request)
request.csp_nonce = SimpleLazyObject(nonce)
if (
self.redirect
and not request.is_secure()
and not any(pattern.search(path) for pattern in
self.redirect_exempt)
):
host = self.redirect_host or request.get_host()
return HttpResponsePermanentRedirect(
"https://%s%s" % (host, request.get_full_path())
)
def process_response(self, request, response):
.................................
if self.csp:
csp_header = '; '.join(
(f'{k} {v}' for k, v in self.csp.items())
)
if self.csp_nonce:
nonce = getattr(request, '_csp_nonce', None)
csp_header += "; 'nonce-%s'" % nonce
response.headers["Content-Security-Policy"] = csp_header
if self.csp_report_only:
csp_header = '; '.join(
(f'{k} {v}' for k, v in self.csp_report_only.items())
)
response.headers["Content-Security-Policy-Report-Only"] =
csp_header
return response
}}}
The CSP and Report-Only are repetitive so will making a method like
csp_policy_builder be apt?
Also this implementation is not the actual representation of the overall
implementation it's just a snippet
3) The CSP nonce context processor:
{{{#!py
def nonce(request):
nonce = request.csp_nonce if hasattr(request, 'csp_nonce') else ''
return {
'CSP_NONCE': nonce
}
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:33>
Comment (by Anvesh Mishra):
Submitted a [https://github.com/django/django/pull/16864 WIP PR]. Open for
suggestions.
--
Ticket URL: <https://code.djangoproject.com/ticket/15727#comment:34>