Content Security Policy can significantly reduce the risk and impact of cross-site scripting attacks in modern browsers.
The web's security model is based on a
same-origin policy. For example,
code from https://mybank.com must have access to only https://mybank.com's
data, and https://evil.example.com must never be allowed access.
Each origin is, in theory, kept isolated from the rest of the web, giving
developers a safe sandbox to build in. In practice, however, attackers have
found several ways to subvert the system.
Cross-site scripting (XSS) attacks, for example, bypass the same-origin policy by tricking a site into delivering malicious code along with the intended content. This is a huge problem, as browsers trust all of the code that shows up on a page as being legitimately part of that page's security origin. The XSS Cheat Sheet is an old but representative cross-section of the methods an attacker might use to violate this trust by injecting malicious code. If an attacker successfully injects any code at all, they've compromised the user session and gained access to private information.
This page outlines Content Security Policy (CSP) as a strategy for reducing the risk and impact of XSS attacks in modern browsers.
Components of CSP
To implement an effective CSP, take the following steps:
- Use allowlists to tell the client what's allowed and what isn't.
- Learn what directives are available.
- Learn the keywords they take.
- Restrict the use of inline code and
eval(). - Report policy violations to your server before enforcing them.
Source allowlists
XSS attacks exploit the browser's inability to distinguish between script that's
part of your application and script that's been maliciously injected by a third
party. For example, the Google +1 button at the bottom of this page loads and
executes code from https://apis.google.com/js/plusone.js in the context of
this page's origin.
We trust that code, but we can't expect the browser to figure out on its own
that code from apis.google.com is safe to run, while code from
apis.evil.example.com probably isn't. The browser happily downloads and
executes any code a page requests, regardless of source.
CSP's Content-Security-Policy HTTP header lets you create an allowlist of
sources of trusted content, and tells the browser to execute or render only
resources from those sources. Even if an attacker can find a hole to inject a
script through, the script won't match the allowlist, and therefore won't be
executed.
We trust apis.google.com to deliver valid code, and we trust ourselves
to do the same. Here's an example policy that allows scripts to execute only
when they come from one of those two sources:
Content-Security-Policy: script-src 'self' https://apis.google.com
script-src is a directive that controls a set of script-related privileges for
a page. This header 'self' as one valid source of script, and
https://apis.google.com as another. The browser can now download and execute
JavaScript from apis.google.com over HTTPS, as well as from the current
page's origin, but not from any other origin. If an attacker injects code into
your site, the browser throws an error and doesn't run the injected script.