Package: django-csp-plus
# Django CSP PlusDjango app for building CSP and tracking violations.This project is based on the excellent `django-csp` project from MDN,with a couple of alterations:1. It includes a violation report tracker2. It stores rules in a model, so they can be edited at runtimeThe `nonce` pattern has been lifted directly.## HistoryThe original reason for forking this from the original was the desire tohave the violation reporting with the same Django project as the sourcepages. I'm sure there is / was an excellent reason for not doing so inthe original, but it's not explained, and Django seems like a great fitfor an HTTP endpoint that can parse JSON requests and store the datasomewhere.The second reason was the experience we had with Sqreen - a fantasticsecurity app that we used from their beta launch through to theiracquisition by Datadog. They have/had a great violation report tool thatallowed you to see how many violations had occurred, and toautomatically add the valid domains to the working CSP, making CSPtrivial to manage (and requiring no restarts).It felt like this is something we could add to the Django adminrelatively easily ("convert this violation report into a rule").The final push was the desire to manage the rules at runtime - running alarge commercial site you never quite know what the marketing team hasjust added to the site, and having to redeploy to unblock their new toolwas a pain.We ended with these requirements:1. Design time base rules2. Runtime configurable rules3. Builtin violation reporting4. Support for nonces5. Ability to exclude specific requests / responses## ImplementationWe have split the middleware in two - `CspNonceMiddleware`, which addsthe `request.csp_nonce` attribute, and `CspHeaderMiddleware`, which addsthe header. Most sites will want both, but you can run one without theother.The baseline, static, configuration of rules is a dict in `settings.py`.This can then be enriched with dynamic rules stored in the `CspRule`model.You can add two special placeholders in the rules: `{nonce}` and`{report-uri}`; if present these will be replaced with the current`request.csp_nonce` and the local violation report URL on each request.The CSP is cached for all requests with the placeholder text in (so it'sthe same for all users / requests).### DirectivesSome directives are deprecated, and others not-yet implemented. Thecanonical example is the `style-src-elem` directive (and its `style-`and `-attr`) siblings which are _not_ supported by Safari. In order tohighlight these the corresponding directive choice labels have beenamended. Treat with caution as setting these attributes may haveunintended consequences.#### Downgrading directivesIn some instances you may want to "downgrade" a directive - for instanceconverting all `script-src-elem` directives to `script-src` (forcompatibility reasons). This can be done using the`CSP_REPORT_DIRECTIVE_DOWNGRADE` setting.## Settings### `CSP_ENABLED``bool`, default = `False`Kill switch for the middleware. Defaults to `False` (disabled).### `CSP_REPORT_DIRECTIVE_DOWNGRADE``dict[str, str]`, default =```python{"script-src-elem": "script-src","script-src-attr": "script-src","style-src-elem": "style-src","style-src-attr": "style-src",}```This is used to transparently "downgrade" any directives to a differentdirective, and is primarily used for managing compatibility.### `CSP_REPORT_ONLY``bool`, default = `True`Set to `True` to run in report-only mode. Defaults to `True`.### `CSP_REPORT_SAMPLING``float`, default = `1.0`Float (0.0-1.0) - used as a percentage of responses on which to includethe `report-uri` directive. This can be used to turn down the noise -once you have a stable CSP there is no point having every single requestinclude the reporting directive - you need a trickle not a flood.### `CSP_REPORT_THROTTLING``float`, default = `0.0`Float (0.0-1.0) - used as a percentage of reporting violation requeststo throttle (throw away). This is used to control potentially maliciousviolation reporting. The reporting endpoint is public, and accepts JSONpayloads, so is open to abuse (sending very large, or malformed JSON)and is a potential DOS vulnerability. If you set this value to 1.0 thenall inbound reporting requests are thrown away without processing. Usein extremis.### `CSP_CACHE_TIMEOUT``int`, default = `600`The cache timeout for the templated CSP. Defaults to 5 min (600s).### `CSP_FILTER_REQUEST_FUNC``Callable[[HttpRequest], bool]` - defaults to returning `True` for allrequestsA callable that takes `HttpRequest` and returns a bool - if False, themiddleware will not add the response header. Defaults to return `True`for all requests.### `CSP_FILTER_RESPONSE_FUNC``Callable[[HttpResponse], bool]` - defaults to `True` for all`text/html` responses.Callable that takes `HttpResponse` and returns a bool - if `False` themiddleware will not add the response header. Defaults to a function thatfilters only responses with `Content-Type: text/html` - which results instatic content / JSON responses _not_ getting the CSP header.### `CSP_DEFAULTS``dict[str, list[str]]`The default (baseline) CSP as a dict of `{directive: values}`. This isextended by the runtime rules (i.e. not overwritten). Defaults to:```python{"default-src": ["'none'"],"base-uri": ["'self'"],"connect-src": ["'self'"],"form-action": ["'self'"],"font-src": ["'self'"],"img-src": ["'self'"],"script-src": ["'self'"],"style-src": ["'self'"],"report-uri": ["{report_uri}"],}```Note the `{report-uri}` value in the default - this is cached as-is,with the local report URL injected into it at runtime.