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.
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).
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.
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.
- W3C documentation : https://www.w3.org/TR/CSP/
- Mozilla documentation : https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/
- Implement nonce with Nginx : https://scotthelme.co.uk/csp-nonce-support-in-nginx/