Content Security Policy is an excellent second-line-of-defence safeguard — it gives extra peace of mind for scenarios such as a previously unknown vulnerability being discovered in a 3rd party JavaScript library used by your otherwise well-tested and secure application. You can find out more here.

It comes at a cost — CSP over years evolved as a relatively complex standard, with plenty of extensions and numerous dos and don'ts based on differences in implementation between various browsers. Here are the best practices and most common mistakes in implementing CSP in real world applications:

  • DO NOT use unsafe-inline or unsafe-eval — these are, as the name suggests, simply unsafe and allow full CSP bypass using JavaScript code injected in the page if an XSS is found.
  • DO NOT a classic origin whitelist — long sequence of script-src 'self' directives are the traditional way of building CSP but it's neither safe nor effective.
  • DO NOT use default-src 'self' — this way you're giving a blanket approval to all kinds of more or less exotic content types, even though you would never use them legitimately on your website (e.g. applet etc)
  • DO NOT use script-src without object-src or default-src 'none' — otherwise an XSS bypass is possible using <object> with a malicious SWF file
  • DO NOT use wildcard origins (asterisk *) or URL schemes — they allow bypass of the policy by including content from completely untrusted domains, or injection through schemes such as javascript:
  • DO use content hashes (e.g. script-src 'sha256-aBC...') for whitelisting trusted inline scripts
  • DO use nonces combined with "strict dynamic" (e.g. script-src 'nonce-XXX...' 'strict-dynamic') to whitelist trusted scripts that load other scripts (chain loading)
  • DO set default-src 'none' and then allow individual content types using their designated directives — this way you not only make the policy more robust but also improve logging precision (with report-uri), because for most browsers reports will use the most general directive that caused the block and, believe me, information that some content was blocked by default-src is pretty useless
  • DO prevent clickjacking with frame-ancestors 'none' directive
  • DO use block-all-mixed-content directive
  • DO use upgrade-insecure-requests directive

This list incorporates guidelines published in CSP Is Dead, Long Live CSP article, as well as our own experience. The engine now displays warnings based on these guidelines if CSP header is found on your website.