Monday Morning with a Content-Security-Policy HTTP Response Header

The story

Mondays are always a unique mixture of a new beginning and unexpected surprises in every office. Sometimes you find a solution for a long-standing problem, but you never know what awaits you in your mailbox after a long, unclouded weekend. The Monday morning, on which my story begins, is a good example for the latter. When I checked my e-mails, a desperate message welcomed me about our recently finished project:

 

Could you please help me? The site is not working on plenty of mobile clients, since we set these http headers, following the request by the security team:

Content-Security-Policy: script-src ‘self’.  Do you have any idea how this happened?

As a junior developer I had no idea what to say, so in my first puzzlement, I tried the requests myself. I found the following error message written in the browsers console:

error message - Content-Security-Policy: script-src 'self'

Soon I started to investigate further and found the following definition:

Content-Security-Policy HTTP response header helps you reduce XSS risks on modern browsers by declaring what dynamic resources are allowed to load via a HTTP Header.

cyberrisks - Content-Security-Policy: script-src 'self'

 

CSP, XSS…. I started to feel like I was in Mr Robot, fighting with some serious hacker teams, then I disenchantedly realized these are very easy-to-understand problems, with which I can easily cope after some further research. If you continue reading, I will present you the results of my research, introducing the basic types of XSS and the reasons why and how to use CSP.

A simple example

In the following paragraph, I will try to explain you how the XSS (cross-site-scripting) attacks work with an extremely simple life-like example. Let’s just imagine that you are the owner of the country’s biggest electrical store chain. As you are trying to keep up with the latest customer preferences, you are maintaining a web shop. To make it more interactive, there is a possibility for every customer to write comments under the vendible. If we take a look at the website and it’s HTML file, they will probably look like this:

 

best store - Content-Security-Policy: script-src 'self'

 

As, of course, your products are of superior quality, this feedback system works like a charm, and makes very good marketing for your company. Your business is flourishing, but then the greedy, shifty owner of the country’s second biggest electrical store chain finds a way to mess up your success. He writes a tricky comment under your products:

sneaky script - Content-Security-Policy: script-src 'self'

 

For the future visitors your HTML will look like this:

 

If you are not well prepared against XSS attacks, this little action may cause you a headache.  As a result of the HTML code above, your website will produce some unexpected behavior:

unexpected - Content-Security-Policy: script-src 'self'

Soon, your website will be flooded by the disgruntled, angry comments from your customers demanding their brand new mobile device. What is worse, the rival company will have all your customers registered e-mail addresses, passwords, and other secure data previously stored in cookies in their browsers. Though it is a very unfortunate story, if you are well prepared, you can easily prevent these kinds of accidents.

A brief summary about the XSS attacks

Come to think of it, cross-site scripting attacks can have various scenarios, and some of these are much more complex and unforeseen, than our electric store’s sad story.  In general, the goal of an XSS attack is always to execute malicious javascript in the victim’s browser. Depending on how this happens, they are divided into three types:

  • Persistent XSS – the malicious string comes from the server (see the example story above)
  • Reflected XSS – the malicious string comes from the victim’s request, for example:  the victim gets an URL than contains a malicious string as a query parameter, falls for the trick and visits it.
  • DOM-based XSS –  the vulnerability is in the client side code. It is very dangerous, because it stays hidden from the server.

Ways to prevent XSS

  • Encoding  the act of escaping user input so that the browser interprets it only as data, not as code. For instance if you use AngularJS, this functionality is already built-in. If you want to display a string type content of your model, it will be encoded, and never interpreted by the browser. For example our webshop with angularJS framework would be something like that:

 

Although in the last comment, the comment.message field’s  value is, for instance  “<script>alert(‘Hi!)<script>” , if we take a look at the compiled HTML file in the browser, the special characters of the string will be encoded:

  • Validation  this step is about  the validation of user inputs, according to given patterns. For example in case of a wysiwyg editor, the html input should not contain <script> tags, as there may be some malicious javascript in there. Also an URL type input should never contain “javascript:” pattern. The invalid input may be rejected, or in some cases it is enough to remove the invalid parts of it.

With the proper use  of encoding and validation, your website will be protected from all types of XSS attacks, but given their diversity, it is not easy to fill all the security gaps and breaches. Using Content Security Policy may give you a helping hand with this issue.

About CSP in general

Basically, Content Security Policy prevents cross-site-scripting by restricting the sources of content (javascript, css,image) loaded by the user agent to those only allowed by the site operator.

The site operator can specify the trusted sources, furthermore the inline scripts and the javascript eval function are not allowed by default. You can enable CSP by setting the ‘Content Security Policy’ HTTP header.

A simple CSP header implementation looks like this: <directive>:<source-expression>.

All the directives describe one type of resource, like javascript(‘script-src’). image(‘img-src’), css (‘style-src’) etc. There is a special directive (‘default-src’), that refers to all non-listed source types.

The source expression should define a server that sources can be downloaded from.

 

Here is a simple example of how you can configure your settings:

In the example above, all kinds of sources, served from the site’s domain will be allowed. In addition, javascript files will be allowed from other.content.delivery.network.com, too. In this case ‘script-src’: ‘self’ should not be forgotten. Otherwise the javascript files from the site’s own domain will not be allowed, as ‘script-src’ overwrites the settings of ‘default-src’.

It is very important to define ‘default-src’ because otherwise the source types not listed will be automatically allowed. For instance, in the following example insecure image or css files will be allowed, too.

If you would like to add inline scripts and style to your code, these can be allowed with ‘script-src’:”unsafe-inline’. If you still would like to use the Javascript ‘eval()’ function, you can enable it by using:’script-src:’unsafe-eval’ settings. These steps are, however, not exactly encouraged, as this way you make your site vulnerable to XSS attacks. Fortunately, CSP provides safe ways to manage these problems, ‘nonce-source’ and ‘hash-source’ directives will allow only specific blocks of content to be executed.

Finally we are done with configuring the CSP settings. If the attacker manages to inject malicious code into the page, it will not execute the injected scripts. Probably it will fail to load the page at all, but at least the attackers won’t access any secure data.

Angular versus CSP

Unlike many other frameworks, Angular v1.1.0+ requires no tweaks to work within a strict CSP.

However, if you’re using an older version of Angular (between v1.0.1 and v1.1.0), you will need  to run it in a “content security mode”. This is done by including the ngCsp directive:

Please take note, that according to the Angular Documentation, you will also need the aforementioned directive, if you aree developing Google Chrome Extensions or Universal Windows Apps. The usage of ng-csp will provide a 30% decrease in the speed of evaluating the Angular expressions.

When necessary, you can specify which of the CSP related Angular features should be deactivated by providing a value for the ng-csp attribute. The options are as follows:

  • no-inline-style: this stops Angular from injecting CSS styles into the DOM
  • no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings

Back to the basics – the solution

Considering the result of my research, I decided to check if any of my own code violates the rules set in the Content Security Policy header.  If you come up against the same problem, I suggest you to check the following things in your HTML:

  • do you have any inline <style> blocks or style attributes?
  • do you have any inline scripts?
  • do you have any DOM element handlers? (eg. onclick)?
  • do you use any javascript pseudo protocol (eg. onclick=”Javascript:function()”)?
  • do you use eval() function or new Function() constructor?
  • do you use any string as the first attribute of the setTimeOut()/setInteral() functions in the HTML?
  • do you use any resources from servers that are not listed in your CSP settings?
  • if you use AngularJS and none of the above listed options helped with your problem, check out ng-csp directive

 

Eventually, the biggest lesson of this story was for me to be a bit more optimistic with these Monday morning surprises. After the first heart attack, they always make me learn things I would otherwise never even think about. And that is an indisputably awesome thing about being a developer! I hope you enjoyed this quick summary, and have taken a liking to learn more about this diverse issue.

 

Csenge Sóti

Csenge Sóti

Web-Developer at Wanari Ltd.
“Life is a series of building, testing, changing and iterating.” -Lauren Mosenthal