diff --git a/apps/guide/settings/base.py b/apps/guide/settings/base.py index e0dd340..526ded0 100644 --- a/apps/guide/settings/base.py +++ b/apps/guide/settings/base.py @@ -67,6 +67,7 @@ MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", + "django_permissions_policy.PermissionsPolicyMiddleware", # Whitenoise middleware is used to server static files (CSS, JS, etc.). # According to the official documentation it should be listed underneath # SecurityMiddleware. @@ -183,6 +184,54 @@ ] +# Security + +# Configure the `Permissions-Policy` header +# https://github.com/adamchainz/django-permissions-policy +PERMISSIONS_POLICY = { + "accelerometer": [], + "ambient-light-sensor": [], + "autoplay": [], + "camera": [], + "display-capture": [], + "document-domain": [], + "encrypted-media": [], + "fullscreen": [], + "geolocation": [], + "gyroscope": [], + "interest-cohort": [], + "magnetometer": [], + "microphone": [], + "midi": [], + "payment": [], + "usb": [], +} + +# Content Security policy settings +# http://django-csp.readthedocs.io/en/latest/configuration.html +if "CSP_DEFAULT_SRC" in env: + MIDDLEWARE.append("csp.middleware.CSPMiddleware") + + # The “special” source values of + # 'self', 'unsafe-inline', 'unsafe-eval', and 'none' must be quoted! + # e.g.: CSP_DEFAULT_SRC = "'self'" Without quotes they will not work as intended. + + CSP_DEFAULT_SRC = env.get("CSP_DEFAULT_SRC").split(",") + if "CSP_SCRIPT_SRC" in env: + CSP_SCRIPT_SRC = env.get("CSP_SCRIPT_SRC").split(",") + if "CSP_STYLE_SRC" in env: + CSP_STYLE_SRC = env.get("CSP_STYLE_SRC").split(",") + if "CSP_IMG_SRC" in env: + CSP_IMG_SRC = env.get("CSP_IMG_SRC").split(",") + if "CSP_CONNECT_SRC" in env: + CSP_CONNECT_SRC = env.get("CSP_CONNECT_SRC").split(",") + if "CSP_FONT_SRC" in env: + CSP_FONT_SRC = env.get("CSP_FONT_SRC").split(",") + if "CSP_BASE_URI" in env: + CSP_BASE_URI = env.get("CSP_BASE_URI").split(",") + if "CSP_OBJECT_SRC" in env: + CSP_OBJECT_SRC = env.get("CSP_OBJECT_SRC").split(",") + # Internationalization # https://docs.djangoproject.com/en/4.0/topics/i18n/ diff --git a/poetry.lock b/poetry.lock index ab68686..f705f54 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "anyascii" @@ -394,6 +394,24 @@ Django = ">=1.8,<5" [package.extras] lint = ["black (==20.8b1)", "flake8 (==3.8.4)", "isort (==5.7.0)"] +[[package]] +name = "django-csp" +version = "3.7" +description = "Django Content Security Policy support." +optional = false +python-versions = "*" +files = [ + {file = "django_csp-3.7-py2.py3-none-any.whl", hash = "sha256:01443a07723f9a479d498bd7bb63571aaa771e690f64bde515db6cdb76e8041a"}, + {file = "django_csp-3.7.tar.gz", hash = "sha256:01eda02ad3f10261c74131cdc0b5a6a62b7c7ad4fd017fbefb7a14776e0a9727"}, +] + +[package.dependencies] +Django = ">=1.8" + +[package.extras] +jinja2 = ["jinja2 (>=2.9.6)"] +tests = ["jinja2 (>=2.9.6)", "mock (==1.0.1)", "pep8 (==1.4.6)", "pytest (<4.0)", "pytest-django", "pytest-flakes (==1.0.1)", "pytest-pep8 (==1.0.6)", "six (==1.12.0)"] + [[package]] name = "django-extensions" version = "3.2.3" @@ -471,6 +489,20 @@ Django = "*" [package.extras] testing = ["django-modelcluster"] +[[package]] +name = "django-permissions-policy" +version = "4.18.0" +description = "Set the draft security HTTP header Permissions-Policy (previously Feature-Policy) on your Django app." +optional = false +python-versions = ">=3.8" +files = [ + {file = "django_permissions_policy-4.18.0-py3-none-any.whl", hash = "sha256:36aeb2ab7e694b8db5a60780c0325608014bbfd10df16cd51ef3b1522f922d23"}, + {file = "django_permissions_policy-4.18.0.tar.gz", hash = "sha256:a6bfd94910f95c0b1c911dbeda6ad340902d3c9caac78d1c20c76f9a4b27929f"}, +] + +[package.dependencies] +Django = ">=3.2" + [[package]] name = "django-redis" version = "5.4.0" @@ -1408,4 +1440,4 @@ testing = ["Pillow (>=9.1.0,<11.0.0)", "Wand (>=0.6,<1.0)", "black (==22.3.0)", [metadata] lock-version = "2.0" python-versions = ">=3.11" -content-hash = "02a15594b4eb36b24c258e247b1ae213e279eaa1eda83ba7ab13d67d21194a58" +content-hash = "7b842ec4825c2108bbcf191dc4c4b81353727a88876093f83e77deacada91410" diff --git a/pyproject.toml b/pyproject.toml index 74843a1..d5f58db 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,8 @@ django-storages = ">=1.14,<1.15" whitenoise = ">=6.6,<6.7" psycopg2 = "2.9.9" wagtail-localize = "1.7rc1" +django-permissions-policy = "^4.13.0" +django-csp = "^3.7" [tool.poetry.group.dev.dependencies] ruff = "^0.1.4" diff --git a/setup.cfg b/setup.cfg index f39f3fb..dfb96ef 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,4 +9,4 @@ omit = *migrations* [coverage:report] -show_missing = True \ No newline at end of file +show_missing = True