mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
feat(security): every page carries a Content-Security-Policy that needs no template change
A small middleware sends object-src 'none', base-uri 'self', form-action 'self' and frame-ancestors 'none': no plugin content, no injected <base> redirecting relative URLs, no form posting to another origin, no framing. script-src and style-src are left out: the templates still hold inline scripts, event handlers and javascript: URLs, which an enforced script policy would block. The middleware is added to the settings template, which the update steps and each Docker container rebuild settings.py from.
This commit is contained in:
parent
75559629e4
commit
6f44461c28
4 changed files with 30 additions and 0 deletions
|
|
@ -7,6 +7,8 @@ from operations import claims, jobs
|
|||
from operations.utils import busy_message, public_error_text, summary
|
||||
|
||||
API_PREFIX = "/api/"
|
||||
# the directives that need no change to the templates' inline scripts and styles
|
||||
CONTENT_SECURITY_POLICY = "object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
|
||||
|
||||
|
||||
def error_text(request, exception):
|
||||
|
|
@ -21,6 +23,16 @@ def error_text(request, exception):
|
|||
return public_error_text(exception)
|
||||
|
||||
|
||||
class ContentSecurityPolicyMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
response = self.get_response(request)
|
||||
response.setdefault("Content-Security-Policy", CONTENT_SECURITY_POLICY)
|
||||
return response
|
||||
|
||||
|
||||
class ExceptionMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ MIDDLEWARE = [
|
|||
"django.contrib.auth.middleware.RemoteUserMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"webvirtcloud.middleware.ContentSecurityPolicyMiddleware",
|
||||
"appsettings.middleware.AppSettingsMiddleware",
|
||||
"webvirtcloud.middleware.ExceptionMiddleware",
|
||||
# last, as django-axes requires
|
||||
|
|
|
|||
15
webvirtcloud/tests/test_csp.py
Normal file
15
webvirtcloud/tests/test_csp.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
"""Every response carries the Content-Security-Policy directives that need no
|
||||
change to the templates' inline scripts and styles."""
|
||||
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
class ContentSecurityPolicyTests(TestCase):
|
||||
def test_pages_and_redirects_carry_the_policy(self):
|
||||
for url in (reverse("accounts:login"), reverse("index")): # a page, and a redirect to the login
|
||||
with self.subTest(url=url):
|
||||
policy = self.client.get(url)["Content-Security-Policy"]
|
||||
self.assertEqual(
|
||||
policy, "object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue