A Content Security Policy (CSP) is a second line of defense against cross-site scripting: even if an attacker injects markup, the browser refuses to run scripts that the policy does not allow.
The target policy
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data:;
font-src 'self';
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
form-action 'self'
No 'unsafe-inline', no 'unsafe-eval', no third-party origins. Everything the page needs is served from your own domain.
What breaks
- Inline event handlers such as
onclick="...". Move them to a JS file and useaddEventListener. - Inline
<script>blocks. Move the code to a static file, or pass data throughdata-*attributes. - Libraries that use
evalornew Function. Choose alternatives, or write the few lines of vanilla JS you actually need. - Third-party CDNs for fonts and scripts. Self-host them: it is also better for privacy and performance.
Structured data is fine
A <script type="application/ld+json"> block is not executable, so browsers do not apply script-src to it. JSON-LD for SEO keeps working.
Roll it out safely
Start with the Content-Security-Policy-Report-Only header and watch the browser console on every page type. Once it is quiet, switch to the enforcing header. Set it in one place (a Django middleware or the reverse proxy) so it cannot drift between environments.