16.09.2019

Content Security Policy header to prevent Cross Site Scripting Attacks

Since the web 2.0, website use more code and resources on client side. This is due to the large number of JavaScript library which allow to have beautiful website with animation and live updating. The JS is present on most website. To use this JS, when the browser downloads the html page, it looks if it need to load other resources like images, style sheet or JS. When all elements are loaded, the browser render the website and run the JS on the client computer.

1. The Attack

The problem with JS code is that the code is executed on the client computer. JS is used for updating the HTML dynamically, call other URL in background, show animations, etc. But, if the website is vulnerable to an XSS (Cross Site Scripting) injection, it can be possible to an attacker to execute some JS on the user computer. The XSS injection is the fact to send HTML with JS code on the website (via a form or directly on the URL for example) and when a user visits the infected page, the browser loads the malicious JS and execute it. Most of the time, the attacker possesses an external server and call a HTML/JS file from this injection. With is JS code, he is able to steal cookie if they are not protected, do change the webpage, add publicity and collect some information about the computer or the local network.

2. Defense

In order to protect user again this type of attack, it is recommended to add the CSP header. This header allows to filter only some source for resources (JS, images, CSS, frames, videos, sounds, etc.).

This is how to implement this header:

Content-Security-Policy: policy directive; policy directive; …

The policy directive depends of resources loaded from the website. If all resources are loaded from the same website, you can use:

Content-Security-Policy: default-src ‘self’

This directive allows the browser to load only resources from the same origin (scheme, host and port).

Posibilities of this header

Possibilities with this header are large, it is possible to force the user to use HTTPS, allow only JS from an URL or match with a regular expression (for example *.company.lu for all sub domain of company.lu). The CSP can also allow a script with a specific hash by checking it when the browser download the JS file. The last option is to add a nonce. This one will be added on a header by the webserver and wrote on the HTML tag via the application server. At each request, the nonce change in order to avoid reuse. These methods allow the developer to mitigate the XSS if good practice are followed for writing the CSP.

Thereby, if an attacker exploits an XSS injection and try to load a JS code from attacker.lu, the CSP header forbids the browser to load the JS code and it is not executed. It is the same if some JS code is added on a JS file, if a hash if present, this one will differ and the browser will block the resource. More information are present on the W3C and Mozilla documentations.

In order to help developers, the CSP provide a reporting mode which shows if a resource do not match the CSP without blocking it, this allows to debug and fine-tune the configuration to be the most restrictive as possible. When it is done, it can be difficult for an attacker to load external resource or exploiting a XSS.

3. Conclusion

The CSP header is a good security against XSS attack, it can be configured with the reporting mode in order to be the most restrictive as possible and complicating the exploitation when the configuration is push in production. The implementation could be easy if the website is well coded at the beginning. However, it could be more difficult in case of inline JS on webpages for example.