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 for an attacker to execute some JS on the user computer. The XSS injection refers to the sending of HTML with JS codes on the website (via a form or directly on the URL for example). When a user visits the infected page, the browser loads the malicious JS and executes it. Most of the time, the attacker possesses an external server and call an HTML/JS file from this injection. With this JS code, he can steal not protected cookie, change the webpage, add publicity, and collect some information about the computer or the local network.
The Content-Security-Policy header, you secret weapon
To protect the user against this type of attacks, it is necessary to add the Content-Security-Policy header. This header allows filtering only some sources for resources (JS, images, CSS, frames, videos, sounds, etc.).
How to implement this header:
Content-Security-Policy: policy directive; policy directive; …
The policy directive depends on resources loaded from the website. If all loaded resources come 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).
Content-Security-Policy header possibilities:
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 subdomain of company.lu). The Content-Security-Policy can also allow a script with a specific hash by checking it when the browser downloads the JS file. The last option is to add a nonce. The web server will add this one on a header and will write on the HTML tag via the application server. At each request, the nonce changes to avoid reuse. These methods allow the developer to mitigate the XSS if good practices are followed for writing the CSP.
Thereby, if an attacker exploits an XSS injection and tries to load a JS code from attacker.lu, the CSP header forbids the browser to load the JS code. The same situation occurs if some JS codes are added on a JS file if a hash. If so, this one will differ and the browser will block the resource. You can find more information in the W3C and Mozilla documentations.
In order to help developers, the CSP provide a reporting mode which shows if a resource does not match the CSP without blocking it. This allows to debug and fine-tune the configuration to be the most restrictive as possible. Once done, it can be difficult for an attacker to load external resource or exploiting an XSS.
The Content-Security-Policy header, good security against XSS attacks
The CSP header is 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 pushed in production. The implementation can be easy as long as the website is well-coded at the beginning. However, it could be more difficult for 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/