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

Write 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
Try it in the editor →

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.

Learn Web Security Foundations for free

20 short lessons with real code and instant checks.

See the whole course →