One of the most common (and most annoying) web application vulnerabilities is XSS (Cross Site Scripting). Depending on the context it can either be an irritation or downright dangerous. To defend against this vulnerability you have a few options; proper input/output escaping (something that should be happening anyway but everyone makes mistakes) or place a Web Application Firewall in the way (does slow down the application). What if there was a better way? A control that didn't rely on developers being forgetful or add extra overhead to the user experience. As a matter of fact there is such a way: Content Security Policy
The Content Security Policy (CSP) is an effective web application security control to prevent XSS and other injection attacks. CSP enacts certain "policies" that are sent to the user's browser. These policies act as a whitelist for where certain resources are allowed to come from.
When you load a webpage, you are downloading JavaScript, CSS, Fonts, Images, and all sorts of elements from other domains. What would happen if an attacker could somehow add their own JavaScript into the mix? It would give an attacker the opportunity to steal credentials, redirect users to a different website, and more! Content Security Policy provides a framework to choose which domains we will trust. This also includes the ability to reject inline JavaScript!
There are two ways to implement a Content Security Policy. The first (and preferred) method is to set it as a response header. The server will issue the CSP header with a "policy" as defined by the developer.
The second way to implement a CSP is to provide it as a "<meta>" tag in the html of the page. Please note that this is not the best way to implement the control, as the policy will not apply to "frame-ancestors", "report-uri", or "sandbox" directives.
In the situation where the CSP is defined as a response header and as a meta tag at the same time Chrome and Firefox will respect whichever policy is the most restrictive
When a CSP is defined as a response header it will take the following form
Content-Security-Policy: script-src 'self' https://maxcdn.bootstrapcdn.com
Here we are defining where JavaScript may be loaded from. Those two locations are "self" (which indicates the domain the page was served from) and "https://maxcdn.bootstrapcdn.com" which is the CDN for Bootstrap. If an attacker was able to either inject malicious JavaScript from a malicious domain, or inject inline JS, the browser would ignore it and throw an error in the browser console.
As you can see, this is a powerful tool in our Application Security Toolbox! And the good news for us is that it doesn't only apply to JavaScript! Content-Security-Policy can be used to restrict a variety of different elements and the origins they are loaded from!
content-security-policy.com provides a list of all the key directives and source options which I will display below.
The following are some important directives that we should point out
It is important to note that by default all policy directives are left open. For example, if we don't specify a list of safe origins for images, an image can be loaded from any domain. The way we get around this is through the "default-src" directive. As mentioned in Google's Web Development Fundamentals "Generally, [default-src] applies to any directive that ends with "-src"". By setting this directive, we are telling the browser to only load a variety of resources from a single domain (so long as you specify it).
CSP is very effective at preventing injection attacks, but wouldn't you want to find and fix the underlying vulnerabilities/bugs? The "report-uri" directive can help in that regard. This directive will ask the browser to report any CSP violations it detects to a specific endpoint through POST requests. This can help you fix any misconfigurations that may exist in your web app.
The greatest power of the CSP is its ability to block inline elements. For example, even if an attacker is able to inject JavaScript into a page it won't trigger if the Content Security Policy is configured correctly.
Unfortunately, many developers will want to still include <script> tags in their HTML to perform some kind of JavaScript. The solution (to make it compatible with CSP) would be to move that code to a separate file that is loaded later. While yes, this does increase the overhead in terms of fetching an additional resource, it will also improve the development process by separating functionality from the HTML document.
While having no inline code is ideal, sometimes there is no way around it. If your dev team cant (for whatever reason) remove the inline code, Content Security Policy does provide a simple workaround through cryptography. By taking the SHA256 (or SHA384, SHA512) hash of the JavaScript and adding this to the CSP response header, the inline JavaScript will be allowed to run. An example of this is found here.
There is a dangerous alternative to using hashes. Simply putting the 'unsafe-inline' source in the CSP will allow any inline scripts to run. This should be a last resort and not something implemented over the long term.
Another great feature of Content Security Policy is that you can ensure your developers are following a basic Application Security Principle: don't use 'eval'. When configured correctly CSP won't allow 'eval' or any similar dangerous functions to trigger. This behavior can be overwritten by the 'unsafe-eval' source.
As mentioned above, the reporting functionality is very beneficial for logging and alerting to issues. If you have a particularly complex app, it may be helpful to only implement the reporting and not actually restrict anything. That is where "Content-Security-Policy-Report-Only" comes in. This header wont block any resources but it will report all violations of the CSP.
This can be incredibly useful if you are planning to change your policies, as you can see ahead of time if anything will break.