|
1 | 1 | CHANGES
|
2 | 2 | =======
|
3 | 3 |
|
| 4 | +4.0 |
| 5 | +=== |
| 6 | + |
| 7 | +This release contains several breaking changes. For a complete migration guide, see: |
| 8 | +https://django-csp.readthedocs.io/en/latest/migration-guide.html |
| 9 | + |
| 10 | +## Breaking Changes |
| 11 | + |
| 12 | +- **Configuration Format**: Moved to dict-based configuration which allows for setting policies for |
| 13 | +both enforced and report-only. Instead of using individual settings with `CSP_` prefixes, you now |
| 14 | +use dictionaries called `CONTENT_SECURITY_POLICY` and/or `CONTENT_SECURITY_POLICY_REPORT_ONLY`. |
| 15 | +([#219](https://github.com/mozilla/django-csp/pull/219)) |
| 16 | + |
| 17 | + You can use Django's check command to automatically identify existing CSP settings and generate a |
| 18 | + template for the new configuration format: |
| 19 | + |
| 20 | + ``` |
| 21 | + python manage.py check |
| 22 | + ``` |
| 23 | + |
| 24 | + This will detect your old `CSP_` prefixed settings and output a draft of the new dict-based |
| 25 | + configuration, giving you a starting point for migration. |
| 26 | + |
| 27 | + **Example:** |
| 28 | + |
| 29 | + Change from: |
| 30 | + ```python |
| 31 | + CSP_DEFAULT_SRC = ["'self'", "*.example.com"] |
| 32 | + CSP_SCRIPT_SRC = ["'self'", "js.cdn.com/example/"] |
| 33 | + CSP_IMG_SRC = ["'self'", "data:", "example.com"] |
| 34 | + CSP_EXCLUDE_URL_PREFIXES = ["/admin"] |
| 35 | + ``` |
| 36 | + |
| 37 | + to: |
| 38 | + ```python |
| 39 | + from csp.constants import SELF |
| 40 | + |
| 41 | + CONTENT_SECURITY_POLICY = { |
| 42 | + "DIRECTIVES": { |
| 43 | + "default-src": [SELF, "*.example.com"], |
| 44 | + "script-src": [SELF, "js.cdn.com/example/"], |
| 45 | + "img-src": [SELF, "data:", "example.com"], |
| 46 | + }, |
| 47 | + "EXCLUDE_URL_PREFIXES": ["/admin"], |
| 48 | + } |
| 49 | + ``` |
| 50 | + |
| 51 | +- **Nonce Configuration**: Switched from specifying directives that should contain nonces as a |
| 52 | +separate list to using a sentinel `NONCE` value in the directive itself. |
| 53 | +([#223](https://github.com/mozilla/django-csp/pull/223)) |
| 54 | + |
| 55 | + **Example:** |
| 56 | + |
| 57 | + Change from: |
| 58 | + ```python |
| 59 | + CSP_INCLUDE_NONCE_IN = ['script-src', 'style-src'] |
| 60 | + ``` |
| 61 | + |
| 62 | + to: |
| 63 | + ```python |
| 64 | + from csp.constants import NONCE, SELF |
| 65 | + |
| 66 | + CONTENT_SECURITY_POLICY = { |
| 67 | + "DIRECTIVES": { |
| 68 | + "script-src": [SELF, NONCE], |
| 69 | + "style-src": [SELF, NONCE], |
| 70 | + } |
| 71 | + } |
| 72 | + ``` |
| 73 | + |
| 74 | +- **Nonce Behavior**: Changed how `request.csp_nonce` works - it is now Falsy |
| 75 | +(`bool(request.csp_nonce)`) until it is read as a string (e.g., used in a template or with |
| 76 | +`str(request.csp_nonce)`). Previously, it always tested as `True`, and testing generated the nonce. |
| 77 | +([#270](https://github.com/mozilla/django-csp/pull/270)) |
| 78 | + |
| 79 | + **Before:** |
| 80 | + ```python |
| 81 | + # The nonce was generated when this was evaluated |
| 82 | + if request.csp_nonce: |
| 83 | + # Do something with nonce |
| 84 | + ``` |
| 85 | + |
| 86 | + **After:** |
| 87 | + ```python |
| 88 | + # This won't generate the nonce, and will evaluate to False until nonce is read as a string |
| 89 | + if request.csp_nonce: |
| 90 | + # This code won't run until nonce is used as a string |
| 91 | + |
| 92 | + # To generate and use the nonce |
| 93 | + nonce_value = str(request.csp_nonce) |
| 94 | + ``` |
| 95 | + |
| 96 | +- Dropped support for Django ≤3.2. |
| 97 | +- Dropped support for Python 3.8. |
| 98 | + |
| 99 | +## New Features and Improvements |
| 100 | + |
| 101 | +- **Dual Policy Support**: Added support for enforced and report-only policies simultaneously using |
| 102 | +the separate `CONTENT_SECURITY_POLICY` and `CONTENT_SECURITY_POLICY_REPORT_ONLY` settings. |
| 103 | + |
| 104 | + **Example:** |
| 105 | + ```python |
| 106 | + from csp.constants import NONE, SELF |
| 107 | + |
| 108 | + # Enforced policy |
| 109 | + CONTENT_SECURITY_POLICY = { |
| 110 | + "DIRECTIVES": { |
| 111 | + "default-src": [SELF, "cdn.example.net"], |
| 112 | + "frame-ancestors": [SELF], |
| 113 | + }, |
| 114 | + } |
| 115 | + |
| 116 | + # Report-only policy (stricter for testing) |
| 117 | + CONTENT_SECURITY_POLICY_REPORT_ONLY = { |
| 118 | + "DIRECTIVES": { |
| 119 | + "default-src": [NONE], |
| 120 | + "script-src": [SELF], |
| 121 | + "style-src": [SELF], |
| 122 | + "report-uri": "https://example.com/csp-report/", |
| 123 | + }, |
| 124 | + } |
| 125 | + ``` |
| 126 | + |
| 127 | +- **CSP Constants**: Added CSP keyword constants in `csp.constants` (e.g., `SELF` instead of |
| 128 | +`"'self'"`) to minimize quoting mistakes and typos. |
| 129 | +([#222](https://github.com/mozilla/django-csp/pull/222)) |
| 130 | + |
| 131 | + **Example:** |
| 132 | + |
| 133 | + Change from: |
| 134 | + ```python |
| 135 | + CSP_DEFAULT_SRC = ["'self'", "'none'"] |
| 136 | + ``` |
| 137 | + |
| 138 | + to: |
| 139 | + ```python |
| 140 | + from csp.constants import SELF, NONE |
| 141 | + |
| 142 | + CONTENT_SECURITY_POLICY = { |
| 143 | + "DIRECTIVES": { |
| 144 | + "default-src": [SELF, NONE], # No need to worry about quoting |
| 145 | + } |
| 146 | + } |
| 147 | + ``` |
| 148 | + |
| 149 | +- Added comprehensive type hints. ([#228](https://github.com/mozilla/django-csp/pull/228)) |
| 150 | +- Added `EXCLUDE_URL_PREFIXES` check not a string. ([#252](https://github.com/mozilla/django-csp/pull/252)) |
| 151 | +- Added support for CSP configuration as sets. ([#251](https://github.com/mozilla/django-csp/pull/251)) |
| 152 | +- Changed `REPORT_PERCENTAGE` to be a float between `0.0` and `100.0` and improved behavior for 100% |
| 153 | +report percentage to always send CSP reports. |
| 154 | +- Added ability to read the nonce after response if it was included in the header. This will raise |
| 155 | +an error when nonce is accessed after response if not already generated. |
| 156 | +([#269](https://github.com/mozilla/django-csp/pull/269)) |
| 157 | +- Made changes to simplify middleware logic and make `CSPMiddleware` easier to subclass. The updated |
| 158 | +middleware returns a PolicyParts dataclass that can be modified before the policy is built. |
| 159 | +([#237](https://github.com/mozilla/django-csp/pull/237)) |
| 160 | + |
| 161 | +## Other Changes |
| 162 | + |
| 163 | +- Added Python 3.13 support. |
| 164 | +- Added support for Django 5.1 and 5.2. |
| 165 | +- Documentation improvements including fixed trusted_types links and clarification on NONE vs Python's None. |
| 166 | +- Documentation note that reporting percentage needs rate limiting middleware. |
| 167 | +- Expanded ruff configuration and moved into pyproject.toml. |
| 168 | + |
| 169 | + |
4 | 170 | 4.0b7
|
5 | 171 | =====
|
6 | 172 | - Removed ``CSPMiddlewareAlwaysGenerateNonce`` middleware that forced nonce headers when not used in
|
|
0 commit comments