Set security headers in django instead of reverse proxy
This commit is contained in:
parent
c87f4eed37
commit
58b40710f0
7 changed files with 41 additions and 27 deletions
|
@ -1,13 +1,8 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% if not user.is_authenticated and goatcounter_domain is not None %}
|
{% if not user.is_authenticated and goatcounter_domain is not None %}
|
||||||
<script>
|
<script async defer src="{% static "vendor/goatcounter.js" %}"
|
||||||
window.goatcounter = {
|
data-goatcounter="https://{{ goatcounter_domain }}/count"></script>
|
||||||
endpoint: 'https://{{ goatcounter_domain }}/count',
|
|
||||||
allow_local: true,
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script async defer src="{% static "vendor/goatcounter.js" %}"></script>
|
|
||||||
<noscript>
|
<noscript>
|
||||||
<img src="https://{{ goatcounter_domain }}/count?p={{ request.get_full_path }}"
|
<img src="https://{{ goatcounter_domain }}/count?p={{ request.get_full_path }}"
|
||||||
alt="GoatCounter tracking pixel">
|
alt="GoatCounter tracking pixel">
|
||||||
|
|
|
@ -106,7 +106,7 @@ def test_has_goatcounter_if_set(client: Client, settings):
|
||||||
settings.GOATCOUNTER_DOMAIN = "gc.gabnotes.org"
|
settings.GOATCOUNTER_DOMAIN = "gc.gabnotes.org"
|
||||||
res = client.get(reverse("articles-list"))
|
res = client.get(reverse("articles-list"))
|
||||||
content = res.content.decode("utf-8")
|
content = res.content.decode("utf-8")
|
||||||
assert "window.goatcounter" in content
|
assert "data-goatcounter" in content
|
||||||
assert f"{settings.GOATCOUNTER_DOMAIN}/count" in content
|
assert f"{settings.GOATCOUNTER_DOMAIN}/count" in content
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,7 @@ MIDDLEWARE = [
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
|
"csp.middleware.CSPMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = "blog.urls"
|
ROOT_URLCONF = "blog.urls"
|
||||||
|
@ -208,3 +209,19 @@ SHORTPIXEL_RESIZE_HEIGHT = int(os.getenv("SHORTPIXEL_RESIZE_HEIGHT", 10000))
|
||||||
GOATCOUNTER_DOMAIN = os.getenv("GOATCOUNTER_DOMAIN")
|
GOATCOUNTER_DOMAIN = os.getenv("GOATCOUNTER_DOMAIN")
|
||||||
|
|
||||||
LOGIN_URL = "admin:login"
|
LOGIN_URL = "admin:login"
|
||||||
|
|
||||||
|
SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin"
|
||||||
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||||
|
SECURE_HSTS_PRELOAD = True
|
||||||
|
SECURE_HSTS_SECONDS = 63072000
|
||||||
|
|
||||||
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
|
# CSP
|
||||||
|
CSP_DEFAULT_SRC = ("'none'",)
|
||||||
|
https_goatcounter_domain = "https://" + GOATCOUNTER_DOMAIN
|
||||||
|
CSP_IMG_SRC = ("'self'", https_goatcounter_domain)
|
||||||
|
CSP_SCRIPT_SRC = ("'self'",)
|
||||||
|
CSP_CONNECT_SRC = ("'self'", https_goatcounter_domain)
|
||||||
|
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
|
||||||
|
CSP_MANIFEST_SRC = ("'self'",)
|
||||||
|
|
|
@ -36,15 +36,6 @@ server {
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_header Content-Security-Policy "frame-ancestors 'none'; default-src 'none'; img-src 'self' https:; script-src 'self'
|
|
||||||
https://gc.gabnotes.org; connect-src https://gc.gabnotes.org; style-src 'self' 'unsafe-inline';
|
|
||||||
font-src 'self'; manifest-src 'self';" always;
|
|
||||||
add_header X-Frame-Options "DENY" always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
||||||
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
|
|
||||||
|
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
listen 80;
|
listen 80;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,15 +37,6 @@ server {
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_header Content-Security-Policy "frame-ancestors 'none'; default-src 'none'; img-src https:; script-src 'self'
|
|
||||||
https://gc.gabnotes.org; connect-src https://gc.gabnotes.org; style-src 'self' 'unsafe-inline';
|
|
||||||
font-src 'self'; manifest-src 'self';" always;
|
|
||||||
add_header X-Frame-Options "DENY" always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
||||||
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
|
|
||||||
|
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
listen 80;
|
listen 80;
|
||||||
}
|
}
|
||||||
|
|
21
poetry.lock
generated
21
poetry.lock
generated
|
@ -163,6 +163,21 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "django-csp"
|
||||||
|
version = "3.7"
|
||||||
|
description = "Django Content Security Policy support."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Django = ">=1.8"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
jinja2 = ["jinja2 (>=2.9.6)"]
|
||||||
|
tests = ["pytest (<4.0)", "pytest-django", "pytest-flakes (==1.0.1)", "pytest-pep8 (==1.0.6)", "pep8 (==1.4.6)", "mock (==1.0.1)", "six (==1.12.0)", "jinja2 (>=2.9.6)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django-debug-toolbar"
|
name = "django-debug-toolbar"
|
||||||
version = "3.2"
|
version = "3.2"
|
||||||
|
@ -637,7 +652,7 @@ multidict = ">=4.0"
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.8"
|
python-versions = "^3.8"
|
||||||
content-hash = "75428f7191094bbd90f5bb60010d46a7bb1d904cbea3abadfe7c97af6db1b1a3"
|
content-hash = "b57e76c611e052a1ece53c34764ddbf0e0f33ff9dafa5193bec5384685cebf01"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
appdirs = [
|
appdirs = [
|
||||||
|
@ -785,6 +800,10 @@ django-cleanup = [
|
||||||
{file = "django-cleanup-5.1.0.tar.gz", hash = "sha256:8976aec12a22913afb3d1fcb541b1aedde2f5ec243e4260c5ff78bb6aa75a089"},
|
{file = "django-cleanup-5.1.0.tar.gz", hash = "sha256:8976aec12a22913afb3d1fcb541b1aedde2f5ec243e4260c5ff78bb6aa75a089"},
|
||||||
{file = "django_cleanup-5.1.0-py2.py3-none-any.whl", hash = "sha256:71e098c7d9ac3f3da40b95cff9c0bc51218d40ef419261232f46ba3141c50acc"},
|
{file = "django_cleanup-5.1.0-py2.py3-none-any.whl", hash = "sha256:71e098c7d9ac3f3da40b95cff9c0bc51218d40ef419261232f46ba3141c50acc"},
|
||||||
]
|
]
|
||||||
|
django-csp = [
|
||||||
|
{file = "django_csp-3.7-py2.py3-none-any.whl", hash = "sha256:01443a07723f9a479d498bd7bb63571aaa771e690f64bde515db6cdb76e8041a"},
|
||||||
|
{file = "django_csp-3.7.tar.gz", hash = "sha256:01eda02ad3f10261c74131cdc0b5a6a62b7c7ad4fd017fbefb7a14776e0a9727"},
|
||||||
|
]
|
||||||
django-debug-toolbar = [
|
django-debug-toolbar = [
|
||||||
{file = "django-debug-toolbar-3.2.tar.gz", hash = "sha256:84e2607d900dbd571df0a2acf380b47c088efb787dce9805aefeb407341961d2"},
|
{file = "django-debug-toolbar-3.2.tar.gz", hash = "sha256:84e2607d900dbd571df0a2acf380b47c088efb787dce9805aefeb407341961d2"},
|
||||||
{file = "django_debug_toolbar-3.2-py3-none-any.whl", hash = "sha256:9e5a25d0c965f7e686f6a8ba23613ca9ca30184daa26487706d4829f5cfb697a"},
|
{file = "django_debug_toolbar-3.2-py3-none-any.whl", hash = "sha256:9e5a25d0c965f7e686f6a8ba23613ca9ca30184daa26487706d4829f5cfb697a"},
|
||||||
|
|
|
@ -40,6 +40,7 @@ pylibmc = "^1.6.1"
|
||||||
django-debug-toolbar = "^3.2"
|
django-debug-toolbar = "^3.2"
|
||||||
whitenoise = {extras = ["brotli"], version = "^5.2.0"}
|
whitenoise = {extras = ["brotli"], version = "^5.2.0"}
|
||||||
rcssmin = "^1.0.6"
|
rcssmin = "^1.0.6"
|
||||||
|
django-csp = "^3.7"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pre-commit = "^2.7"
|
pre-commit = "^2.7"
|
||||||
|
|
Reference in a new issue