Advertisement

Client-Side Security Best Practices

by

Thanks to HTML5, more and more of an applications' logic is transferred from server-side to client-side. This requires front-end developers to focus more on security. In this article I will show you how to make your apps more secure. I will focus on techniques that you may not have heard about, instead of just telling you that you have to escape HTML data entered in by users.


Don't Even Think About HTTP

Of course I don't want you to serve your content with FTP or plain TCP. What I mean is that if you want your users to be safe when using your website, you need to use SSL (HTTPS). And not only for login sites, or valuable information. For all of your content. Otherwise, when someone is accessing your app from a public network, what they see may be malformed by some hacker inside this network. This is called a main-in-the-middle attack:

main-in-the-middle

When you use SSL, all of the data is encrypted before it's sent, so even if the attacker gets it, he would not be able to modify or capture it. This is by far the most important step in securing your app.

Strict Transport Security

This HTTP header can come in handy if you want to serve your content using only SSL. When it's issued by the server (or a <meta> tag, but that will allow at least one request to be HTTP), no insecure traffic will come from the browser to your server. It is used like this:

Strict-Transport-Security: max-age=3600; includeSubDomains

The includeSubDomains part is optional, it allows you to declare that you also want all of the sub-domains to be accessed using HTTPS. The max-age option sets how long (in seconds) the pages should be served using SSL. Sadly, only Firefox, Chrome and Opera are supporting Strict Transport Security.

Secure and HttpOnly

Another way to further improve the security on both HTTP and HTTPS are these two cookie attributes: Secure and HttpOnly. The first one allows a cookie to be sent only on SLL connection. The second one may sound as the exact opposite, but it's not. It's telling the browser that the cookie can only be accessed using HTTP(S) protocol, so it cannot be stolen using, for example, JavaScript's document.cookie.


Make XSS Less Harmful With Content Security Policy

Content Security Policy allows you to define the origin of all scripts, images etc. on your site.

If you think your XSS filter will stop all possible XSS attacks check how many ways there are to perform these attacks and think again. Of course securing your app to stop all of these may be a problem and may slow it down, but there is a solution.

It's called Content Security Policy. It allows you to define the origin of all scripts, images etc. on your site. It also blocks all inline scripts and styles, so even if someone can inject a script tag into a comment or post, the code would not be executed. The CSP is an HTTP header (which can also be set using HTML <meta> tag), which looks like this:

Content-Security-Policy: policy

Where policy is a set of CSP directives. Here are the possible options:

  • script-src - sets acceptable sources of JavaScript code
  • style-src - defines acceptable origins of CSS styles
  • connect-src - specifies the servers the browser can connect to using XHR, WebSockets and EventSource
  • font-src - lists allowed sources of fonts
  • frame-src - defines what origins should be allowed in iframes
  • img-src - sets allowed image sources
  • media-src - lists origins that can serve video and audio files
  • object-src - same as above but for Flash and other plugins

If a directive is not set, the browser assumes that all origins are allowed. This can be changed by setting the default-src option. What you set there will be applied to all unset directives. There is also a sandbox option, which makes the webpage load as an iframe with the sandbox attribute. An example usage of the CSP header would look like this:

Content-Security-Policy: default-src: 'self'; script-src: https://apis.google.com;

It allows all of the assets to be loaded only from the application's origin (the 'self' attribute) and also allows you to load scripts from the Google APIs server. There is a lot of flexibility when defining CSP, and when used properly it will greatly improve the security of your webpage.

Drawbacks

The thing to remember when using CSP is that, by default, all inline JavaScript will not be executed. This also includes:

  • inline event listeners: like <body onload="main();">
  • all javascript URLs: like <a href="javascript:doTheClick()">

This is because the browser cannot distinguish your inline code from the hacker's inline code. You will have to replace them by adding event listeners with addEventListener or some framework's equivalent. This is not a bad thing ultimately, as it forces you to separate your application's logic from its graphical representation which you should be doing anyway. CSP also (by default) blocks all eval()-ish code, including strings in setInterval/setTimeout and code like new Function('return false').

Availability

CSP is available in most of the modern browsers. Firefox, Chrome and Opera (mobile too) use the standard Content-Security-Policy header. Safari (iOS too) and Chrome for Android use the X-WebKit-CSP header. IE10 (with support limited only to the sandbox directive) uses X-Content-Security-Policy. So, thanks to Internet Explorer, you can't just use only CSP (unless you will use something like Google Chrome Frame), but you can still use it to improve the security on the real browsers and to prepare your app for the future.


Use Cross Origin Resource Sharing Instead of JSONP

JSONP is currently the most used technique to get resources from other servers despite the same-origin policy. Usually, you just create the callback function in your code and pass the name of that function to the URL from which you want to get the data, like this:

function parseData(data) {
	...
}
<script src="http://someserver.com/data?format=jsonp&callback=parseData"></script>

But by doing this, you are creating a big security risk. If the server that you are getting data from is compromised, a hacker can add his malicious code and for example, steal your user's private data, because actually, you are getting JavaScript using this request - and the browser will run all of the code just like with a normal script file.

The solution here is Cross Origin Resource Sharing. It allows your data provider to add a special header in responses so that you can use XHR to retrieve that data, then parse and verify it. This removes the risk of getting malicious code executed on your site.

The implementation requires the provider only to add the following special header in responses:

Access-Control-Allow-Origin: allowed origins

This can be just a few allowed origins separated with spaces, or a wildcard character: * to let every origin request the data.

Availability

All current versions of modern browsers support CORS, with the exception of Opera Mini.

Of course, the bigger problem here is that service providers would have to add CORS support, so it's not completely dependent on the developer.


Sandbox Potentially Harmful Iframes

An iframe with the sandbox attribute will not be able to navigate the window, execute scripts, lock the pointer, show pop-ups or submit forms.

If you are using iframes to load content from external sites, you may want to secure them too. This can be done using the sandbox iframe attribute. An iframe with such an attribute empty (but present) will not be allowed to navigate the window, execute scripts, lock the pointer, show pop-ups or submit forms. The frame will also have a unique origin, so it can't use localStorage or anything related to the same-origin policy. You can of course allow some of them, if you want, by adding one or more of these values into the attribute:

  • allow-same-origin - the frame will have the same origin as the site, instead of the unique one
  • allow-scripts - the frame will be allowed to execute JavaScript
  • allow-forms - the frame will be able to submit forms
  • allow-pointer-lock - the frame will have access to the Pointer Lock API
  • allow-popups - the frame will be allowed to show pop-ups
  • allow-top-navigation - the frame will be able to navigate the window

Availability

The sandbox iframe attribute is supported in all modern browsers, with the exception of Opera Mini.


Conclusion

So that's it. I hope you've learned some new techniques that you can use in your future projects to protect your applications. Thanks to HTML5, we can now do amazing things with our websites, but we have to think about security from the first line of code if we want them to be resistant against attacks.

Advertisement