Add a Content-Security-Policy in Report-Only mode (refs #3041) - #3042
Add a Content-Security-Policy in Report-Only mode (refs #3041)#3042tonghuaroot wants to merge 2 commits into
Conversation
www.python.org currently sends no Content-Security-Policy header. This adds one via django-csp as defense-in-depth against XSS, starting in Report-Only mode so violations can be collected and the allowlist tuned before the policy is enforced. The middleware follows the existing XFrameOptionsMiddleware pattern. Refs python#3041.
ffd5621 to
69eef9e
Compare
sethmlarson
left a comment
There was a problem hiding this comment.
Thanks, two comments:
| X_FRAME_OPTIONS = "SAMEORIGIN" | ||
| SILENCED_SYSTEM_CHECKS = ["security.W019"] | ||
|
|
||
| ### django-csp (Content-Security-Policy) |
There was a problem hiding this comment.
Add a comment to remove this and our dependency on django-csp when we upgrade to Django 6.0.
There was a problem hiding this comment.
Done, added a note to drop django-csp once we move to Django 6.0.
|
|
||
| # Report-Only first: collect violations and tune the allowlist before | ||
| # enforcing. Rollout tracked in #3041. | ||
| CONTENT_SECURITY_POLICY_REPORT_ONLY = { |
There was a problem hiding this comment.
Can we add a test case that checks which HTTP header is emitted? Want to make sure Content-Security-Policy-Report-Only is emitted, not Content-Security-Policy so we don't break everyone on rollout.
There was a problem hiding this comment.
Added a test that checks the Report-Only header is set and the enforcing one is not. Runs green.
|
@tonghuaroot Are you still interested in landing this PR? |
|
Yes, still keen to land it. Pushed both of your changes and it's ready for another look. |
Part of #3041 (adds the CSP in Report-Only mode; enforcing and origin tuning to follow).
What this does
www.python.org currently sends no
Content-Security-Policyheader. This adds one viadjango-cspas defense-in-depth against XSS.It ships in Report-Only mode: responses carry
Content-Security-Policy-Report-Onlyand no enforcingContent-Security-Policy, so nothing is blocked for users. The point of this first step is to collect violation reports and tune the allowlist before switching to an enforced policy.Changes
pyproject.toml/uv.lock: adddjango-csp==4.0.pydotorg/settings/base.py:csp.middleware.CSPMiddlewaretoMIDDLEWARE, alongside the existingXFrameOptionsMiddleware(which is how the site already sets a security header from Django).CONTENT_SECURITY_POLICY_REPORT_ONLYpolicy with a strict starting set of directives.Starting policy
These are intentionally strict so the Report-Only telemetry surfaces every inline script/style and third-party origin that needs a nonce, hash, or allowlist entry. Follow-ups from #3041: add a report endpoint, tune the origins, wire nonces into the base templates, then flip Report-Only to enforcing.
Verification
Smoke-tested the config against django-csp 4.0 in isolation: it emits the
Content-Security-Policy-Report-Onlyheader with the directives above and no enforcingContent-Security-Policyheader, so pages are never blocked.