--- title: Content Security Policy (CSP) description: "A header that limits where scripts, styles, and images can come from. It helps contain XSS, but needs a staged rollout." canonical: https://penasihathosting.com/en/hosting-wiki/csp type: wiki locale: en updated: 2026-10-29 author: Willya Randika --- # Content Security Policy (CSP) ## Overview - **Summary:** A header that limits where scripts, styles, and images can come from. It helps contain XSS, but needs a staged rollout. - **Author:** Willya Randika ([profile](/penulis/willya-randika)) ## Article CSP is an HTTP header that decides which sources may load scripts, styles, images, fonts, and connections. It does not close every XSS hole, but it limits what injected code can do. If an attacker adds a script tag, the browser refuses to run it from a domain you did not allow. ## The directives you will use most `default-src` is the fallback for every resource. `script-src` controls JavaScript, including inline scripts and workers. `style-src` controls CSS. `img-src` controls images. `connect-src` controls fetch, XHR, WebSocket, and beacons. `frame-ancestors` stops other sites from embedding the page, while `form-action` limits where forms may submit. `'self'` means the same origin. A nonce or hash allows a specific script without opening every inline script. Avoid `'unsafe-inline'` in `script-src`; it makes XSS protection much weaker. ## An example header from the app ```http Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://cdn.example.com; connect-src 'self' https://api.example.com; frame-ancestors 'self'; base-uri 'self'; form-action 'self' ``` The nonce in the header must match the nonce rendered by the app in the script tag. The app generates a random nonce per request, uses that value in the HTML, and sends the same header. Do not generate a separate nonce in Nginx because it will not match the HTML. ## Start with report-only Do not enforce the full policy on day one. Use `Content-Security-Policy-Report-Only` first. The browser reports violations without blocking resources. Open DevTools Console, look for “Refused to load” messages, then fix chat widgets, analytics, fonts, and payment iframes that are not allowed yet. Once the violation list is clean, enforce one directive at a time. Test login, checkout, and forms before tightening the policy. Send reports to your own endpoint with `report-to` or `report-uri`, and cap the log size so it does not flood the server. ## What makes CSP fail A policy copied from another site often blocks important assets. Allowing `unsafe-inline` to avoid work weakens the main protection. Forgetting `frame-ancestors` leaves the page embeddable. And CSP does not replace input validation or output escaping. CSP complements [HSTS](/en/hosting-wiki/hsts), which secures transport, and a [WAF](/en/hosting-wiki/waf), which filters requests at the server. They work at different layers. If the application loads resources from another origin, configure [CORS](/en/hosting-wiki/cors) as well. ## FAQ The overhead is usually small. It grows when there are many violation reports or the policy is applied by a slow app layer. Measure with DevTools before drawing conclusions. No. CSP is a browser control. A WAF inspects requests at the server. They handle different threats. Add the font domain to `font-src` and `style-src`, or self-host the fonts. Do not reach for `*` just to silence the error.