#15727: Add support for Content-Security-Policy (CSP) to core
-------------------------------+-----------------------------------------
Reporter: db.pub.mail@… | Owner: Anvesh Mishra
Type: New feature | Status: assigned
Component: HTTP handling | Version: dev
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 1
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+-----------------------------------------
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>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/01070186d7ec5ae4-470589f4-50cc-4a84-8347-6181872286d7-000000%40eu-central-1.amazonses.com.