Content-Security-Policy Generator
Directives in, a deployable CSP header out - with the usual self-defeating mistakes flagged.
Output — csp.txt
About this tool
Build a Content-Security-Policy directive by directive and output it as an HTTP header, an Apache or nginx line, a PHP call or a meta tag. The notes call out the settings that quietly defeat the policy - unsafe-inline, a bare wildcard, a missing default-src - and the directives a meta tag cannot express at all. Start in report-only mode; the tool explains why.
Deploy it in report-only mode first
Content-Security-Policy-Report-Only sends the browser the same policy and asks it to report violations instead of enforcing them. Nothing breaks, and your report endpoint fills up with every inline script, third-party widget and analytics beacon you had forgotten about. Read that list for a week, fix the policy, then switch to the enforcing header.
You can ship both headers at once - report-only for the policy you are working towards, enforcing for the one you already trust. That is how you tighten a policy on a live site without a maintenance window.
unsafe-inline is the whole ballgame
A CSP exists to stop injected script from executing. 'unsafe-inline' in script-src allows every inline <script> block and every onclick attribute - which is precisely the mechanism XSS uses. A policy with it is documentation, not a defense.
The way out is a nonce: put a fresh random value in the header on every response (script-src 'nonce-abc123') and the same value on each script tag you trust. It has to be per-response and unpredictable, or an attacker just reads the nonce out of the page and reuses it. Styles are the harder half in practice, since a lot of libraries write inline style attributes.
Frequently asked questions
Where should the header be set - server or application?
Either works. The server config (Apache, nginx) is simpler and covers static files too. The application is the right place once you need a per-response nonce, because the value has to change on every request. Do not set it in both: two policies do not merge - the browser enforces both, and only what passes each one is allowed.
Does a meta tag work as well as the header?
Mostly, and it is a reasonable option on shared hosting where you cannot set headers. But frame-ancestors, report-uri, report-to and sandbox are ignored in a meta tag, and the policy only applies to content after the tag - so it must be the first thing in <head>.
Do I still need X-Frame-Options?
frame-ancestors 'none' replaces it and is more expressive. Keeping X-Frame-Options costs one line and covers browsers that never implemented frame-ancestors, which by now is a very small share. If both are present, browsers that understand CSP use frame-ancestors and ignore the older header.
What breaks first when I enable a CSP?
Inline scripts and styles, then third-party embeds - analytics, chat widgets, maps, YouTube - and then fonts loaded from a different origin than the stylesheet that asks for them. The browser console names the blocked resource and the directive that blocked it, which makes the fix mechanical once you are looking at it.