Skip to content

Commit 802cb98

Browse files
authored
Merge pull request #49 from maykinmedia/issue/42-headers-for-CSP-and-HSTS
🔧[#42] add HSTS & CSP settings
2 parents d26d0bb + 7ec82db commit 802cb98

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

open_api_framework/conf/base.py

+63
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
# External applications.
204204
"axes",
205205
"django_filters",
206+
"csp",
206207
"corsheaders",
207208
"vng_api_common",
208209
"notifications_api_common",
@@ -241,6 +242,7 @@
241242
"django.contrib.messages.middleware.MessageMiddleware",
242243
"django.middleware.clickjacking.XFrameOptionsMiddleware",
243244
"axes.middleware.AxesMiddleware",
245+
"csp.contrib.rate_limiting.RateLimitedCSPMiddleware",
244246
]
245247

246248
ROOT_URLCONF = f"{PROJECT_DIRNAME}.urls"
@@ -559,6 +561,9 @@
559561
),
560562
)
561563

564+
if IS_HTTPS:
565+
SECURE_HSTS_SECONDS = 31536000
566+
562567
X_FRAME_OPTIONS = "DENY"
563568

564569
#
@@ -932,3 +937,61 @@ def init_sentry(before_send: Callable | None = None):
932937
default=7,
933938
help_text="The amount of time after which request logs should be deleted from the database",
934939
) # number of days
940+
941+
942+
#
943+
# Django CSP settings
944+
#
945+
# explanation of directives: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
946+
# and how to specify them: https://django-csp.readthedocs.io/en/latest/configuration.html
947+
#
948+
# NOTE: make sure values are a tuple or list, and to quote special values like 'self'
949+
950+
# ideally we'd use BASE_URI but it'd have to be lazy or cause issues
951+
CSP_DEFAULT_SRC = [
952+
"'self'",
953+
] + config("CSP_EXTRA_DEFAULT_SRC", default=[], split=True)
954+
955+
CSP_REPORT_PERCENTAGE = config("CSP_REPORT_PERCENTAGE", 1.0) # float between 0 and 1
956+
957+
CSP_FORM_ACTION = (
958+
config(
959+
"CSP_FORM_ACTION",
960+
default=["\"'self'\""]
961+
+ config("CSP_EXTRA_FORM_ACTION", default=[], split=True),
962+
split=True,
963+
)
964+
+ CORS_ALLOWED_ORIGINS
965+
)
966+
967+
CSP_IMG_SRC = CSP_DEFAULT_SRC + config("CSP_EXTRA_IMG_SRC", default=[], split=True)
968+
969+
# affects <object> and <embed> tags, block everything by default but allow deploy-time
970+
# overrides.
971+
CSP_OBJECT_SRC = config("CSP_OBJECT_SRC", default=["\"'none'\""], split=True)
972+
973+
# we must include this explicitly, otherwise the style-src only includes the nonce because
974+
# of CSP_INCLUDE_NONCE_IN
975+
CSP_STYLE_SRC = CSP_DEFAULT_SRC
976+
CSP_SCRIPT_SRC = CSP_DEFAULT_SRC
977+
978+
# firefox does not get the nonce from default-src, see
979+
# https://stackoverflow.com/a/63376012
980+
CSP_INCLUDE_NONCE_IN = ["style-src", "script-src"]
981+
982+
# directives that don't fallback to default-src
983+
CSP_BASE_URI = ["'self'"]
984+
985+
# Frame directives do not fall back to default-src
986+
CSP_FRAME_ANCESTORS = ["'none'"] # equivalent to X-Frame-Options: deny
987+
CSP_FRAME_SRC = ["'self'"]
988+
# CSP_NAVIGATE_TO = ["'self'"] # this will break all outgoing links etc # too much & tricky, see note on MDN
989+
# CSP_SANDBOX # too much
990+
991+
CSP_UPGRADE_INSECURE_REQUESTS = False # TODO enable on production?
992+
993+
CSP_EXCLUDE_URL_PREFIXES = (
994+
# ReDoc/Swagger pull in external sources, so don't enforce CSP on API endpoints/documentation.
995+
"/api/",
996+
"/admin/",
997+
)

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ dependencies = [
3939
"djangorestframework-gis>=1.0",
4040
"django-filter>=24.2",
4141
"drf-spectacular>=0.27.2",
42+
"django-csp>=3.8",
4243
"djangorestframework-inclusions>=1.2.0",
4344
"commonground-api-common>=1.12.1",
4445
"mozilla-django-oidc-db>=0.19.0",

0 commit comments

Comments
 (0)