advanced 3 min answer

In October 2020 the ICO fined British Airways 20 million pounds over its 2018 breach, in which a modified third-party script on payment pages sent customer card details to an attacker-controlled host, affecting over 400,000 customers. A team proposes a strict nonce-based content security policy in response. What does that buy, what does it cost, and what does it not cover?

cspnoncemagecartthird-party-scriptspayments
Show the full answer Hide the answer

What is gained

A skimming attack of that shape needs one thing: the ability to run attacker-chosen JavaScript in the page's origin, with access to form fields and the network. A strict content security policy attacks exactly that capability.

The mechanism matters. An allowlist of hostnames is weak, because allowlisted origins commonly host content that can be used to execute arbitrary code, and because a compromised allowlisted third party is still allowed. A nonce-based policy inverts it: the server generates a fresh random value per response, puts it in the policy header and on each script tag it intends to run, and the browser refuses any script without the current nonce. Injected markup cannot guess it. Adding strict-dynamic lets trusted scripts load their own dependencies, which is what makes the policy deployable on a real site.

Against the specific attack: a modified script served from an allowlisted origin still runs, so the policy alone does not stop a compromised dependency executing. What it does stop is injected inline script and unlisted origins, and with connect-src restricted it also stops the exfiltration leg — the attacker's own collection host is not a permitted destination, so the stolen data has nowhere to go. That second half is the part teams forget and the part that would have mattered here.

What is paid

  • Dynamic nonces mean the HTML cannot be cached as a static document, because the nonce must change per response. Sites with a fully cached shell have to move it to the edge or accept a hole.
  • Inline scripts and styles have to be enumerated, which means real work in legacy pages and templates, plus whatever your tag manager injects.
  • Third parties break, noisily and repeatedly. Some inject inline handlers, some use eval, some load from origins they do not document. Each needs a conversation with a vendor whose support desk has not heard of the policy.
  • Report-only mode is a prerequisite and takes weeks. Deploy in report-only, collect violations from real traffic, fix, then enforce. Enforcing first takes checkout down.
  • It needs an owner. A policy is a living configuration, and one emergency exception for a marketing tag reopens the hole permanently.

What it does not cover

A supply-chain compromise of a script you deliberately load. If the attacker modifies a file on a host you allow and your nonce is on the tag, the browser has no reason to object. That gap needs different tools: subresource integrity so a modified file with a changed hash is refused — usable only for files with stable content, which excludes most tag-managed scripts — plus not loading third-party scripts on the payment page at all, and putting the card fields in a payment provider's iframe so they are not in your origin.

That last point is the honest hierarchy of controls: isolate the sensitive fields, reduce the number of third parties on that page to zero, then apply the policy as defence in depth. A strict policy on a checkout page carrying nine tags is a reasonable second line for a decision that should not have been made.

When this is the wrong priority

On a site with no forms and no payment path, the policy protects mainly against defacement, and the effort is better spent elsewhere. It is also the wrong first move if you have never inventoried your third-party scripts: the inventory usually finds two or three nobody can justify, and removing them is cheaper and more effective than constraining them. Order the work by consequence — payment and authentication pages first, marketing pages last — and choose report-only mode for a whole quarter if the estate is old, because a broken checkout costs more than the attack you are preventing is likely to.