Clickjacking and HTTP security headers (CSP, X-Frame-Options)
Some attacks do not need a bug in the application’s logic. They exploit the freedom browsers give to pages. Fortunately, a server can tell the browser to be stricter through a handful of HTTP response headers. Setting them properly is one of the cheapest and most effective improvements an organisation can make, and checking them is one of the first things a tester does.
Scope reminder
Reading the response headers of a page is passive and harmless, but constructing tricks that mislead real users is not. The experiments in this lesson stay in your lab. The conclusions you reach on real sites are reported to their owners through proper channels, never exploited.
Clickjacking
In clickjacking (also called UI redress), an attacker’s page loads the target site inside a frame, makes that frame invisible or transparent, and positions it over something attractive, like a button saying “Win a prize”. The victim thinks they click the attractive button but actually click the hidden button of the real site, for instance “Confirm the purchase” or “Delete my account”. The click is genuine, performed by the real user, in their real session.
An analogy: someone slides a transparent sheet over a petition form, with a different title beneath. You sign at the spot they point to, but your signature lands on the document underneath.
Which pages are concerned?
Only pages that can be loaded in a frame and contain a sensitive one-click action. A pure information page has little to lose. Login-protected pages with buttons that change settings, make payments or grant permissions are the main concern. Because the attack tricks the user into a single click, actions that require typing or multi-step confirmation are harder to abuse (though not impossible).
The defences
The page must tell the browser who may display it inside a frame.
X-Frame-Options: an older header with the valuesDENY(never in a frame) orSAMEORIGIN(only from the same site).Content-Security-Policywithframe-ancestors: the modern equivalent, more flexible, e.g.frame-ancestors 'none'orframe-ancestors 'self'.
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Setting both is common, to cover all browsers. Some applications use “frame-busting” JavaScript instead; it is unreliable and should not be the only defence.
Testing in your lab
- Request a sensitive page in Burp and examine the response headers. Are
X-Frame-Optionsorframe-ancestorspresent? - If both are missing, build, on your own machine, a local page that embeds your lab application inside a frame. If the application displays inside it, the control is absent.
- Note which sensitive actions would be exposed.
The Web Security Academy has clickjacking labs, with the page and the frame already set up, if you want to see it in action in a legal environment.
Content Security Policy (CSP)
A Content Security Policy is a header that gives the browser a list of approved sources for scripts, styles, images, frames and other content. If the page tries to load or run something that does not match, the browser refuses. It is a powerful safety net against XSS: even if an attacker manages to insert markup, the browser will not run script from an unapproved place.
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'self'
Read this policy aloud: “by default only load content from my own site; scripts only from my own site; no plug-in objects; nobody may frame me; the base URL cannot be altered”. Each directive covers a type of resource.
| Directive | Controls |
|---|---|
default-src | The fallback for resource types not listed individually |
script-src | Where scripts may come from |
style-src | Where stylesheets may come from |
img-src | Where images may come from |
frame-ancestors | Who may embed this page in a frame |
object-src | Plug-in content, normally set to 'none' |
base-uri | The allowed values for the page’s base URL |
Weak CSP patterns
A policy can exist and still be nearly useless. When reviewing one, look for:
'unsafe-inline'inscript-src: allows inline scripts, which is exactly what most XSS injections use. A nonce or hash-based approach is much better.'unsafe-eval': allows evaluating strings as code.- Wildcards such as
*or very broad hosts that attackers can use to host their own scripts. - No
object-srcorbase-urirestrictions.
Developers often deploy a policy in report-only mode first (Content-Security-Policy-Report-Only), which logs violations without blocking, so they can adjust before enforcing it. A site that only has the report-only version is not yet protected.
The MDN documentation and the OWASP Cheat Sheet Series, at developer.mozilla.org and owasp.org, provide precise references for all directives.
Other useful security headers
| Header | Purpose |
|---|---|
Strict-Transport-Security | Tells the browser to use HTTPS only for this site for a set period |
X-Content-Type-Options: nosniff | Stops the browser from guessing a file’s type, preventing content from being treated as a script when it was not declared so |
Referrer-Policy | Controls how much of the URL is shared with other sites when following links |
Permissions-Policy | Restricts browser features such as camera, microphone or geolocation for the page |
Cross-Origin-Opener-Policy and related headers | Isolate the page from other windows and origins |
No header replaces fixing the flaw itself: these are defence-in-depth measures, whose value is that they limit the damage when something else goes wrong.
Checking headers efficiently
In Burp, open a response and read its headers. Make a table of the headers present and absent for your lab application:
Page: /account (training application)
X-Frame-Options: absent
Content-Security-Policy: absent
Strict-Transport-Security: absent (HTTP-only lab, not applicable)
X-Content-Type-Options: absent
Referrer-Policy: absent
Remember that training applications deliberately omit many of these. In a real assessment, a missing header is usually a low or informational finding on its own, and its severity depends on context: a missing frame protection on a page with a one-click sensitive action is more significant than on a static brochure page. Good reports explain that context.
Tip
Avoid the temptation to pad a report with dozens of “missing header” findings. Group them in one finding titled “Missing browser security headers”, list the headers and the recommended values, and focus the reader’s attention on the high-impact issues.
Your turn: build a header review
For your lab application, capture the response to the home page and to an account page in Burp. Fill in a table of the five headers above (present/absent, value). Then write a recommended policy that you would give to the developers, including a simple CSP and a frame protection.
See a solution
An example recommendation for a simple application serving its own scripts and styles:
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains
Explain that the CSP must first be tried in report-only mode to see which legitimate resources would be blocked, and that the HSTS header applies once the site is served over HTTPS. Your finding is classified as low severity, with clickjacking raised to medium if a sensitive one-click action exists on the framed page.
Key takeaways
- Clickjacking tricks users into clicking a hidden framed page; defend with
frame-ancestorsin CSP andX-Frame-Options. - A Content Security Policy restricts the sources of scripts and other resources, limiting the damage of XSS.
- Weak policies (
'unsafe-inline', wildcards, report-only only) give little protection. - Other headers such as HSTS,
nosniff, Referrer-Policy and Permissions-Policy add defence in depth. - Headers do not replace fixing flaws; report them with context and group minor ones.
With chapter 4 behind you, you know how browsers can be turned against their users. In chapter 5, we move to questions of who may do what: access control and business logic.