Directives, sources & fallbacks
Content Security Policy
Lesson 8 of 20 · 13 min · Module 2: Safe HTML and pages
A Content Security Policy tells the browser which scripts, styles, images and connections a page may use. Even when an attacker manages to inject markup, a good policy stops the browser from running it.
Start this lesson →Free. No installation: you write and run the code in your browser, and it is checked automatically.
By the end, you’ll be able to…
- Read the directives and sources of a policy
- Spot the sources that weaken a policy
- Know which directives fall back to default-src
The idea
A policy is a list of directives separated by semicolons, each with its allowed sources, such as default-src 'self'; script-src 'self'; object-src 'none'. 'unsafe-inline' allows inline scripts and event attributes, which is exactly what XSS needs, and sources such as * or https: allow scripts from anywhere. Strong policies also set object-src 'none', base-uri and frame-ancestors. The box starts with the policy that protects this preview.
Content-Security-Policy: default-src 'self'; script-src 'self';
object-src 'none'; base-uri 'none'; frame-ancestors 'self'
01How a policy reaches the browser
Servers send it in the Content-Security-Policy response header, and the browser enforces it for that page. Content-Security-Policy-Report-Only reports problems without blocking anything, which is a safe way to try a new policy on a live site.
02Fallbacks and exceptions
script-src, style-src, img-src, connect-src and object-src fall back to default-src when they are missing. base-uri, form-action and frame-ancestors do not, so a policy without them leaves those doors open.
default-src 'self' → scripts only from your own site
default-src 'self'; script-src * → scripts from anywhere
03Nonces instead of 'unsafe-inline'
When a page needs inline scripts, give each one a random nonce attribute that changes with every response, and list it in the policy as 'nonce-…'. Injected scripts do not know the nonce, so they are blocked, and browsers that support nonces ignore 'unsafe-inline'.
Your turn
auditPolicy(policy). Split the policy into directives at ;, and each directive into a name and sources at spaces, ignoring capital letters, extra spaces and empty parts; when a directive appears twice, only the first counts. Script sources come from script-src, or from default-src when it is missing, and the same goes for object-src. Return, in this order, the codes that apply: no-default-src; unsafe-inline and unsafe-eval when the script sources contain those keywords; scripts-from-anywhere when there are no script sources or they include *, http:, https: or data:; plugins-allowed unless the object sources are exactly 'none'; no-base-uri; no-frame-ancestors.What the checks look for
- A strong policy has no warnings
- Missing directives are reported
- Unsafe keywords are found
- Scripts fall back to default-src
- Wide sources such as https: count as anywhere
- Capital letters, spaces and empty parts are handled
- Only the first copy of a directive counts
- The page explains your audit
Take this with you
Restrict scripts to known sources, avoid 'unsafe-inline', and set object-src, base-uri and frame-ancestors.
Go a little further
The policy in the box protects this preview and allows 'unsafe-eval', because running your code needs it. Write a policy for an ordinary page that loads scripts only from its own site and one CDN, with no warnings.