Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to django-csp 4.0 #4800

Merged
merged 5 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 39 additions & 31 deletions privaterelay/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
import django_stubs_ext
import markus
import sentry_sdk
from csp.constants import NONE, SELF, UNSAFE_INLINE
from decouple import Choices, Csv, config
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.logging import ignore_logger

from .types import RELAY_CHANNEL_NAME
from .types import CONTENT_SECURITY_POLICY_T, RELAY_CHANNEL_NAME

if TYPE_CHECKING:
import wsgiref.headers
Expand Down Expand Up @@ -183,36 +184,42 @@
empty_hash = base64.b64encode(sha256().digest()).decode()
_CSP_STYLE_HASHES.append(f"'sha256-{empty_hash}'")

CSP_DEFAULT_SRC = ["'self'"]
CSP_CONNECT_SRC = [
"'self'",
"https://www.google-analytics.com/",
"https://www.googletagmanager.com/",
"https://location.services.mozilla.com",
"https://api.stripe.com",
BASKET_ORIGIN,
] + _ACCOUNT_CONNECT_SRC
CSP_FONT_SRC = ["'self'"] + _API_DOCS_CSP_FONT_SRC + ["https://relay.firefox.com/"]
CSP_IMG_SRC = ["'self'"] + _AVATAR_IMG_SRC + _API_DOCS_CSP_IMG_SRC
CSP_SCRIPT_SRC = (
["'self'"]
+ (["'unsafe-inline'"] if _CSP_SCRIPT_INLINE else [])
+ [
"https://www.google-analytics.com/",
"https://www.googletagmanager.com/",
"https://js.stripe.com/",
]
)
CSP_WORKER_SRC = _API_DOCS_CSP_WORKER_SRC or None
CSP_OBJECT_SRC = ["'none'"]
CSP_FRAME_SRC = ["https://js.stripe.com", "https://hooks.stripe.com"]
CSP_STYLE_SRC = (
["'self'"]
+ (["'unsafe-inline'"] if _CSP_STYLE_INLINE else [])
+ _API_DOCS_CSP_STYLE_SRC
+ _CSP_STYLE_HASHES
)
CSP_REPORT_URI = config("CSP_REPORT_URI", "")
CONTENT_SECURITY_POLICY: CONTENT_SECURITY_POLICY_T = {
"DIRECTIVES": {
"default-src": [SELF],
"connect-src": [
SELF,
"https://www.google-analytics.com/",
"https://www.googletagmanager.com/",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: thanks!

"https://location.services.mozilla.com",
"https://api.stripe.com",
BASKET_ORIGIN,
groovecoder marked this conversation as resolved.
Show resolved Hide resolved
],
"font-src": [SELF, "https://relay.firefox.com/"],
"frame-src": ["https://js.stripe.com", "https://hooks.stripe.com"],
"img-src": [SELF],
"object-src": [NONE],
"script-src": [
SELF,
"https://www.google-analytics.com/",
"https://www.googletagmanager.com/",
"https://js.stripe.com/",
],
"style-src": [SELF],
}
}
CONTENT_SECURITY_POLICY["DIRECTIVES"]["connect-src"].extend(_ACCOUNT_CONNECT_SRC)
CONTENT_SECURITY_POLICY["DIRECTIVES"]["font-src"].extend(_API_DOCS_CSP_FONT_SRC)
CONTENT_SECURITY_POLICY["DIRECTIVES"]["img-src"].extend(_AVATAR_IMG_SRC)
CONTENT_SECURITY_POLICY["DIRECTIVES"]["img-src"].extend(_API_DOCS_CSP_IMG_SRC)
CONTENT_SECURITY_POLICY["DIRECTIVES"]["style-src"].extend(_API_DOCS_CSP_STYLE_SRC)
CONTENT_SECURITY_POLICY["DIRECTIVES"]["style-src"].extend(_CSP_STYLE_HASHES)
if _CSP_STYLE_INLINE:
CONTENT_SECURITY_POLICY["DIRECTIVES"]["script-src"].append(UNSAFE_INLINE)
if _API_DOCS_CSP_WORKER_SRC:
CONTENT_SECURITY_POLICY["DIRECTIVES"]["worker-src"] = _API_DOCS_CSP_WORKER_SRC
if _CSP_REPORT_URI := config("CSP_REPORT_URI", ""):
CONTENT_SECURITY_POLICY["DIRECTIVES"]["report-uri"] = _CSP_REPORT_URI

REFERRER_POLICY = "strict-origin-when-cross-origin"

Expand Down Expand Up @@ -317,6 +324,7 @@
"rest_framework",
"rest_framework.authtoken",
"corsheaders",
"csp",
"waffle",
"privaterelay.apps.PrivateRelayConfig",
"api.apps.ApiConfig",
Expand Down
66 changes: 65 additions & 1 deletion privaterelay/types.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,69 @@
"""Types for the privaterelay app"""

from typing import Literal
from typing import Literal, TypedDict

RELAY_CHANNEL_NAME = Literal["local", "dev", "stage", "prod"]

# django-csp 4.0: types for CONTENT_SECURITY_POLICY in settings.py

# Note: this will need adjustments to uplift to django-csp
# For example, the django-csp docs say 'sequence' rather than 'list',
# and appear more flexible about sending strings or lists.
_SERIALIZED_SOURCE_LIST = list[str]
CSP_DIRECTIVES_T = TypedDict(
"CSP_DIRECTIVES_T",
{
# CSP Level 3 Working Draft, Directives (section 6)
# https://www.w3.org/TR/CSP/#csp-directives
# 6.1 Fetch Directives
"child-src": _SERIALIZED_SOURCE_LIST,
"connect-src": _SERIALIZED_SOURCE_LIST,
"default-src": _SERIALIZED_SOURCE_LIST,
"font-src": _SERIALIZED_SOURCE_LIST,
"frame-src": _SERIALIZED_SOURCE_LIST,
"img-src": _SERIALIZED_SOURCE_LIST,
"manifest-src": _SERIALIZED_SOURCE_LIST,
"media-src": _SERIALIZED_SOURCE_LIST,
"object-src": _SERIALIZED_SOURCE_LIST,
"script-src": _SERIALIZED_SOURCE_LIST,
"script-src-elem": _SERIALIZED_SOURCE_LIST,
"script-src-attr": _SERIALIZED_SOURCE_LIST,
"style-src": _SERIALIZED_SOURCE_LIST,
"style-src-elem": _SERIALIZED_SOURCE_LIST,
"style-src-attr": _SERIALIZED_SOURCE_LIST,
# 6.2 Other Directives
"webrtc": Literal["'allow'", "'block'"],
"worker-src": _SERIALIZED_SOURCE_LIST,
# 6.3 Document Directives
"base-uri": _SERIALIZED_SOURCE_LIST,
"sandbox": str | list[str], # sequence of tokens in CSP 3
# 6.4 Navigation Directives
"form-action": _SERIALIZED_SOURCE_LIST,
"frame-ancestors": _SERIALIZED_SOURCE_LIST,
"navigate-to": _SERIALIZED_SOURCE_LIST,
# 6.5 Reporting Directives
"report-uri": str | list[str], # sequence of uri-references in CSP 3
"report-to": str,
# "require-sri-for": _SERIALIZED_SOURCE_LIST,
# 6.6 Directives Defined in Other Documents
"block-all-mixed-content": bool, # Deprecated.
"upgrade-insecure-requests": bool,
# CSP2 items removed in CSP3
# https://www.w3.org/TR/CSP2/#directives
"plugin-types": _SERIALIZED_SOURCE_LIST,
# Deprecated, from MDN
"prefetch-src": _SERIALIZED_SOURCE_LIST,
"referrer": str,
# Experimental items, from MDN
"fenced-frame-src": _SERIALIZED_SOURCE_LIST,
"require-trusted-types-for": str,
"trusted-types": str,
},
total=False,
)


class CONTENT_SECURITY_POLICY_T(TypedDict, total=False):
EXCLUDE_URL_PREFIXES: list[str]
DIRECTIVES: CSP_DIRECTIVES_T
REPORT_PERCENTAGE: int
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ module = [
"botocore.config",
"botocore.exceptions",
"codetiming",
"csp.constants",
"debug_toolbar",
"dj_database_url",
"django_filters.*",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Django==4.2.13
dj-database-url==2.2.0
django-allauth[socialaccount]==0.63.3
django-cors-headers==4.4.0
django-csp==3.8
django-csp==4.0b1
groovecoder marked this conversation as resolved.
Show resolved Hide resolved
django-debug-toolbar==4.4.2
django-filter==24.2
django-ipware==7.0.1
Expand Down