Protection against XSS vulnerabilities with CSP headers (Content Security Policy)

XSS vulnerabilities (Cross-Site Scripting), in 3rd position of the last OWASP TOP 10, are a door to get into IT systems (ports scanning, exploits, etc.) and a threat for users (authentication information theft). Traditional countermeasures are input filtering and output encoding to avoid executions of malicious scripts on users computers.

Principe

Another way to protect against this kind of vulnerabilitiy is to set up the Content-Security-Policy HTTP header to define the strategy to control contents downloaded by the web page. The CSP principle is to enumerate a white list of allowed sources used for javascript, CSS, fonts, form POST, AJAX requests, etc.

Available sources are :

  • self : current DNS
  • none : fordidden
    • all : all DNS
  • list of DNS separated by whitespaces.

If an element is not configured, the value of default-src will be used instead.

default-src has 2 more possible values :

  • unsafe-inline : allow inline scripts execution (<script></script>). With CSP, they are forbidden by default
  • unsafe-eval : allow the eval() method

In addition to ressources enumerated above, more options are available :

  • Manage the Anti-CSS behavior provided by web browsers
  • nonce management for inline scripts (CSP v2)

Content download

Almost all elements (fonts, CSS files, javascript files, images, iframe, etc.) downloaded by a web page can be controlled with CSP. For each of these elements, it’s possible to define one or more trusted sources.

For example :

  • Javascript and CSS : any file from : https://cdn.azure.com
  • Pictures : any picture from : http://images.azure.com
    • Inline scripts (<script></script>) are forbidden
  • For other content, allow only the current DNS

will be translated with the following HTTP header :

Content-Security-Policy: default-src 'self' ; script-src https://cdn.azure.com; style-src https://cdn.azure.com; img-src http://images.azure.com;

All parameters are available here.

Sending content

In the same way, it’s possible to define a policy for requests sending contents from the web page (AJAX requests and form post).

For example :

  • AJAX/WebSocket requests : Allow only requests to following DNS : https://api.monsite.com et https://api.sitetiers.com
  • Form post : Allow only requests to the current DNS

will be translated with the following HTTP header :

Content-Security-Policy: connect-src https://api.sitetiers.com https://api.monsite.com; form-action 'self' ;

Theses parameters can be combined with the previous example.

Reporting mode

Setting up CSP with a bad configuration can have a major impact on a website. If a source is forgotten, we can easily browse a website without javascript or CSS files loaded

In order to test the header before going to production, the Content-Security-Policy-Report header will not block ressources but will display errors in the browser console

Example :

CSP report

CSP also provides a parameter called report-uri to notify an URL with a POST request when a rule is violated.

Example of received report request :

report-uri

Compatibility and versions

CSP header version 1 is compatible with all major web browsers :

Compatibility CSP

Source : http://caniuse.com/#feat=contentsecuritypolicy

For version 2 it’s not the case :

Compatibility CSP2

Source : http://caniuse.com/#feat=contentsecuritypolicy2

For incompatible web browsers, the header ignored.

A draft for the 3rd version has been released and is available here.

Implementation

For the CSP implementation, you only need to add the HTTP header on your server responses. It’s generally posible on all web frameworks.

To keep your CSP rules maintainable some libraries are available. For example :

Web servers can also be configured to automatically add the header on outgoing requests.