mirror of
https://github.com/pretix/pretix.git
synced 2026-08-26 13:14:40 +00:00
Improved merging of CSP headers
This commit is contained in:
@@ -141,11 +141,20 @@ class SecurityMiddleware(MiddlewareMixin):
|
|||||||
h = {}
|
h = {}
|
||||||
for part in header.split(';'):
|
for part in header.split(';'):
|
||||||
k, v = part.strip().split(' ', 1)
|
k, v = part.strip().split(' ', 1)
|
||||||
h[k.strip()] = v
|
h[k.strip()] = v.split(' ')
|
||||||
return h
|
return h
|
||||||
|
|
||||||
def _render_csp(self, h):
|
def _render_csp(self, h):
|
||||||
return "; ".join(k + ' ' + v for k, v in h.items())
|
return "; ".join(k + ' ' + ' '.join(v) for k, v in h.items())
|
||||||
|
|
||||||
|
def _merge_csp(self, a, b):
|
||||||
|
for k, v in a.items():
|
||||||
|
if k in b:
|
||||||
|
a[k] += b[k]
|
||||||
|
|
||||||
|
for k, v in b.items():
|
||||||
|
if k not in a:
|
||||||
|
a[k] = b[k]
|
||||||
|
|
||||||
def process_response(self, request, resp):
|
def process_response(self, request, resp):
|
||||||
if settings.DEBUG and resp.status_code >= 400:
|
if settings.DEBUG and resp.status_code >= 400:
|
||||||
@@ -155,23 +164,23 @@ class SecurityMiddleware(MiddlewareMixin):
|
|||||||
|
|
||||||
resp['X-XSS-Protection'] = '1'
|
resp['X-XSS-Protection'] = '1'
|
||||||
h = {
|
h = {
|
||||||
'default-src': "{static}",
|
'default-src': ["{static}"],
|
||||||
'script-src': '{static} https://checkout.stripe.com https://js.stripe.com',
|
'script-src': ['{static}', 'https://checkout.stripe.com', 'https://js.stripe.com'],
|
||||||
'object-src': "'none'",
|
'object-src': ["'none'"],
|
||||||
# frame-src is deprecated but kept for compatibility with CSP 1.0 browsers, e.g. Safari 9
|
# frame-src is deprecated but kept for compatibility with CSP 1.0 browsers, e.g. Safari 9
|
||||||
'frame-src': '{static} https://checkout.stripe.com https://js.stripe.com',
|
'frame-src': ['{static}', 'https://checkout.stripe.com', 'https://js.stripe.com'],
|
||||||
'child-src': '{static} https://checkout.stripe.com https://js.stripe.com',
|
'child-src': ['{static}', 'https://checkout.stripe.com', 'https://js.stripe.com'],
|
||||||
'style-src': "{static}",
|
'style-src': ["{static}"],
|
||||||
'connect-src': "{dynamic} https://checkout.stripe.com",
|
'connect-src': ["{dynamic}', 'https://checkout.stripe.com"],
|
||||||
'img-src': "{static} data: https://*.stripe.com",
|
'img-src': ["{static}', 'data:', 'https://*.stripe.com"],
|
||||||
# form-action is not only used to match on form actions, but also on URLs
|
# form-action is not only used to match on form actions, but also on URLs
|
||||||
# form-actions redirect to. In the context of e.g. payment providers or
|
# form-actions redirect to. In the context of e.g. payment providers or
|
||||||
# single-sign-on this can be nearly anything so we cannot really restrict
|
# single-sign-on this can be nearly anything so we cannot really restrict
|
||||||
# this. However, we'll restrict it to HTTPS.
|
# this. However, we'll restrict it to HTTPS.
|
||||||
'form-action': "{dynamic} https:",
|
'form-action': ["{dynamic}', 'https:"],
|
||||||
}
|
}
|
||||||
if 'Content-Security-Policy' in resp:
|
if 'Content-Security-Policy' in resp:
|
||||||
h.update(self._parse_csp(resp['Content-Security-Policy']))
|
self._merge_csp(h, self._parse_csp(resp['Content-Security-Policy']))
|
||||||
|
|
||||||
staticdomain = "'self'"
|
staticdomain = "'self'"
|
||||||
dynamicdomain = "'self'"
|
dynamicdomain = "'self'"
|
||||||
|
|||||||
@@ -33,5 +33,5 @@ class ChartContainingView:
|
|||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
resp = super().get(request, *args, **kwargs)
|
resp = super().get(request, *args, **kwargs)
|
||||||
# required by raphael.js
|
# required by raphael.js
|
||||||
resp['Content-Security-Policy'] = "script-src {static} 'unsafe-eval'; style-src {static} 'unsafe-inline'"
|
resp['Content-Security-Policy'] = "script-src 'unsafe-eval'; style-src 'unsafe-inline'"
|
||||||
return resp
|
return resp
|
||||||
|
|||||||
Reference in New Issue
Block a user