Introduction to Content Security Policy

Read­ing Time: 3 min­utes

Con­tent secu­ri­ty pol­i­cy (CSP) is an extra lay­er of secu­ri­ty that helps to pro­tect web­sites from cross-site script­ing (XSS). The core idea of CSP is to enforce a set of rules described either in the head­er of a HTTP response or in the HTML head ele­ment. Using CSP in com­bi­na­tion with tra­di­tion­al meth­ods such as input san­itza­tion and out­put encod­ing is a great way to enhance the secu­ri­ty of a web­site. The stan­dard is gov­erned by W3 Web Appli­ca­tion Secu­ri­ty Work­ing Group and the ver­sion 2 is cur­rent­ly the most wide­spread with a large major­i­ty of browsers sup­port­ing it1.

There are two ways to enable CSP: either via intro­duct­ing HTTP response head­er Con­tent-Secu­ri­ty-Pol­i­cy that defines the pol­i­cy or describ­ing it in the meta tag of a HTML doc­u­ment. In case of using HTML tags, the tag has to be placed as ear­ly to the doc­u­ment as pos­si­ble because all the resources before the tag will be loaded and parsed with­out any restric­tions and there’s a pos­si­bil­i­ty that one of these resources might tam­per the pol­i­cy described in the tag. If both the response head­er and the meta tag are described, then the stricter pol­i­cy is tak­en into account. In gen­er­al it seems to be more rea­son­able to describe CSP rules in the HTTP head­ers as it is more straight­for­ward to use and offers report-only func­tion­al­i­ty described lat­er.
A poten­tial CSP rule set could look like this:

The pol­i­cy con­sists of rules sep­a­rat­ed by semi­colons where each rule describes the tar­get (whether it applies to scripts, images, stylesheets etc.) and the per­mit­ted sources. For exam­ple, the rule below per­mits to load scripts only from the domain where the web­site is host­ed.

The table below describes the most impor­tant tar­gets of CSP.

block-all-mixed-con­tentblocks load­ing any assets over HTTP when the page is loaded via HTTPS
con­nect-srcrestricts URLs which can be loaded in scripts. For exam­ple, dis­ables ille­gal XHRs.
default-srcA default pol­i­cy used if a direc­tive is miss­ing. Should be used always.
font-srcSpec­i­fies cor­rect sources for fonts
script-srcSpec­i­fies cor­rect sources for scripts
report-uriURI to send reports of vio­la­tion of a pol­i­cy
style-srcSpec­i­fies cor­rect sources for styles

‘self’Match­es the cur­rent domain
‘unsafe-inline’Allows exe­cut­ing inline CSS and JS
https://example.comAllows resources only from over HTTPS
https://*.example.comAllows resources from all sub­do­mains of*Allows resources only from over HTTPS using any port

As it can be seen from the table above, CSP allows using wild­card syn­tax, which enables to cre­ate fine-grained set­up in order to avoid acci­den­tal secu­ri­ty holes. As always with secu­ri­ty, it is wise to be as restric­tive as pos­si­ble.

Inline scripts

CSP is meant to pro­tect a site from adver­saries, while per­mit­ting the real author as much free­dom as pos­si­ble. A quite com­mon sce­nario is that an own­er of a web­site wants to add an inline script like Google Ana­lyt­ics, but block every­one else from inject­ing inline resources. How to achieve it con­sid­er­ing that not describ­ing rule ‘unsafe-inline’ blocks even non-mali­cious inline scripts? CSP spec­i­fi­ca­tion allows the usage of nonce, where the pol­i­cy spec­i­fies an allowed nonce and the per­mit­ted inline resource tag has to have an attribute called “nonce” with exact­ly the same val­ue.
For exam­ple, spec­i­fy­ing the fol­low­ing pol­i­cy allows inject­ing scripts with a nonce val­ue of EDNnf03nceIOfn39fn3e9h3sdfa.

A pos­si­ble inline script that is per­mit­ted to exe­cute could be like this:

As the attack­er does not know the nonce (because nonce, by def­i­n­i­tion, can be used only once and has to be gen­er­at­ed on every page load), then the mali­cious inline resources won’t be exe­cut­ed by the brows­er.


CSP has a  unique fea­ture which per­mits send­ing vio­la­tion reports to a  URL in case of an attempt to load a for­bid­den resource. In order to spec­i­fy the URL, CSP sep­ci­fies direc­tive report-uri fol­lowed by the URL.

The reports are sent via POST request, where the request body could be some­thing like this:

In addi­tion to block­ing and report­ing, CSP also pro­vides a report-only mode where noth­ing is blocked, but all the banned sources are report­ed. This is a per­fect way to test CSP before actu­al­ly start­ing to block ille­gal sources or even use it as hon­ey­pot to learn the behav­ior of mali­cious users. Adding HTTP head­er Con­tent-Secu­ri­ty-Pol­i­cy-Report-Only to the response enables the report-only mode. Both the Con­tent-Secu­ri­ty-Pol­i­cy and Con­tent-Secu­ri­ty-Pol­i­cy-Report-Only can be used at the same time. How­ev­er, it is not pos­si­ble to enable report-only mode using HTML meta tags.


CSP is a great addi­tion­al lay­er of secu­ri­ty that enables to whitelist the sources of assets that are allowed to exe­cute. Pro­vid­ed that the rules are prop­er­ly con­fig­ured, then the attack­ers should have hard time inject­ing their own sources to the site. As always, it is bet­ter to be safe than sor­ry and con­fig­ur­ing CSP as strict­ly as pos­si­ble is a good idea. In addi­tion, even though CSP helps us to secure web­sites, just rely­ing only on it is too risky and the oth­er stan­dard meth­ods like san­i­tiz­ing input and escap­ing out­put should also be used.