Stopping malicious attacks and hacks In Angularjs

To be able to allow secure access to legitimate users, there has to be an element of trust between the server and the browser. Unfortunately, there are a number of attacks that can take advantage of this trust. With the correct support on the server, angularjs can provide protection against these security holes.

Preventing cookie snooping (man-in-the-middle attacks)

Whenever you pass data over HTTP between a client and a server, there is an opportunity for third parties to snoop on secure information, or even worse, access your cookies to hijack your session and access the server, as though they were you. This is often referred to as a “man-in-the-middle” attack, see http://en.wikipedia.org/wiki/Man-in-the-middle_attack. The easiest way to prevent these attacks is to use HTTPS rather than HTTP.

Note

Any application, in which sensitive data passes between the application and the server should use HTTPS to ensure that this data is encrypted.

By encrypting the connection using HTTPS, we prevent sensitive data from being read as it passes between the client and the server, and also we prevent unauthorized users from reading authentication cookies from our requests and hijacking our session.

In our application, the requests to the MongoLab DB are already sent over HTTPS from our server. To provide complete security from this kind of snooping, we should also ensure that our client interacts with our server over HTTPS as well. Mostly, this is just a case of getting the server to listen over HTTPS, and the client to make requests over HTTPS.

Implementing this on the server is dependent on your choice of back-end technology, and is beyond the scope of this book. But in Node.js you could use the httpsmodule as shown in the following code:

var https = require('https');
var privateKey  =
  fs.readFileSync('cert/privatekey.pem').toString();
var certificate =
  fs.readFileSync('cert/certificate.pem').toString();
var credentials = {key: privateKey, cert: certificate};
var secureServer = https.createServer(credentials, app);
secureServer.listen(config.server.securePort);

On the client side, we just have to ensure that the URL used to connect to the server is not hardcoded to the HTTP protocol. The easiest way to do this is not to provide a protocol at all in the URL.

angular.module('app').constant('MONGOLAB_CONFIG', {
  baseUrl: '/databases/',
  dbName: 'ascrum'
});

In addition, we should also ensure that the authentication cookie is restricted to HTTPS requests only. We can do this by setting the httpOnly and secure options to true, when creating the cookie on the server.

Preventing cross-site scripting attacks

A cross-site-scripting attack (XSS) is where an attacker manages to inject client-side script into a web page, when viewed by another user. This is particularly bad if the injected script makes a request to our server, because the server assumes that it is the authenticated user who is making the request and allows it.

There are a wide variety of forms in which XSS attacks can appear. The most common are where user-provided content is displayed without being properly escaped to prevent malicious HTML from being rendered. The next section explains how we can do this on the client, but you should also ensure that any user-provided content is sanitized on the server, before being stored or sent back to the client.

Securing HTML content in angularjs expressions

angularjs escapes all HTML in text that is displayed through the ng-bind directive, or template interpolation (that is text in {{curly braces}}). For example, using the following model:

$scope.msg = 'Hello, <b>World</b>!';

And the markup fragment looks as follows:

<p ng-bind="msg"></p>

The rendering process will escape the <b> tags, so they will appear as plain text, and not as markup:

<p>Hello, &lt;b&gt;World&lt;/b&gt;!</p>

This approach provides a pretty good defense against XSS attacks in general. If you actually want to display text that is marked up with HTML, then you must either trust it completely, in which case you can use the ng-bind-html-unsafe directive, or sanitize the text by loading the ngSanitizemodule, and then using the ng-bind-html directive.

The following binding will render the <b> tags as HTML to be interpreted by the browser:

<p ng-bind-html-unsafe="msg"></p>

Sanitizing HTML

angularjs has one more directive that will selectively sanitize certain HTML tags, while allowing others to be interpreted by a browser, which is ng-bind-html. Its usage is similar to the unsafe equivalent:

<p ng-bind-html="msg"></p>

In terms of escaping, the ng-bind-html directive is a compromise between behavior of ng-bind-html-unsafe (allow all HTML tags) and ng-bind (allow no HTML tags at all). It might be a good option for cases where we want to allow some HTML tags to be entered by users.

Note

The sanitization uses a whitelist of safe HTML tags, which is quite extensive. The main tags that will be sanitized include the <script> and <style> elements, as well as attributes that take URLs such as href, src, and usemap.

The ng-bind-html directive resides in a separate module (ngSanitize), and requires inclusion of an additional source file: angular-sanitize.js. You must declare a dependency on the ngSanitize module if you plan to use the ng-bind-html directive, as shown in the following code:

angular.module('expressionsEscaping', ['ngSanitize'])
  .controller('ExpressionsEscapingCtrl', function ($scope) {
    $scope.msg = 'Hello, <b>World</b>!';
  });

The ng-bind-html directive uses the $sanitize service, which is also found inside the ngSanitize module. This service is a function that takes a string, and then returns a sanitized version of the string, as described in the following code:

var safeDescription = $sanitize(description);

Note

Unless you are working with any existing legacy systems (For example CMS, back-ends sending HTML, and so on), markup in the model should be avoided. Such markup can’t contain angularjs directives and requires the ng-bind-html-unsafe or ng-bind-html directive to obtain the desired results.

Preventing cross-site request forgery

In any application where the server must trust who the user is, that is, they are logged in, and allows them access to actions on the server based on that trust, there is the potential for other sites to pretend to be you, and then get access to those actions themselves. This is called cross-site request forgery (XSRF). If you visit an evil site when you are already logged into a secure site, the evil site’s web page could post to your secure site, since it trusts that you are currently authenticated.

This attack is often in the form of a fraudulent src attribute on an <img> tag, which the user inadvertently loads by browsing to an evil page, while still logged into a secure site. When the browser tries to load the image, it actually makes a request to the secure site.

<img src="http://my.securesite.com/createAdminUser?username=badguy">

The solution is for the server to provide a secret to the browser, which can only be accessed by JavaScript running on the browser, and so would not be available in the src attribute. Any request to the server should include this secret in its headers to prove it is authentic.

The $http service has this solution built-in, in order to protect against such an attack. You must arrange for the server to set a token in the session cookie called XSRF-TOKEN, on the first GET request by the application. This token must be unique for this session.

In the client application, the $http service will extract this token from the cookie, and then attach it as a header (called X-XSRF-TOKEN) to every HTTP request it makes. The server must check the token on each request, and then block access if it is not valid. The angularjs team recommends that the token is a digest of your site’s authentication cookie with salt for added security.

Preventing the JSON injection vulnerability

There is a JSON injection vulnerability that allows evil third party websites to access your secure JSON resources, if they return JSON arrays. This is done by effectively loading the JSON as a script in a web page, and then executing it.

The $http service has a built-in solution to protect against this. To prevent the browser from being able to execute the JSON returned from the secure resource, you can arrange for your server to prefix all the JSON requests with the ")]}',\n" string, which is not legal JavaScript, and so cannot be executed. The $http service automatically strips this prefix string, if it appears from any JSON response. For example, if your JSON resource returns the following array:

['a,'b','c']

This is vulnerable to the JSON injection attack. Instead, the server should return:

)]}',
['a','b','c']

This is not valid JavaScript. It cannot be executed by the browser, and so is no longer vulnerable to attack. The $http service will automatically strip off this invalid prefix, if found, before returning the valid JSON in its response object.

Deven Rathore

Deven is an Entrepreneur, and Full-stack developer, Constantly learning and experiencing new things. He currently runs CodeSource.io and Dunebook.com.

Published by
Deven Rathore

Recent Posts

How to Create a Custom Online Learning Platform

In the last few years, e-learning has become really popular. Coursera has recently surveyed and…

4 weeks ago

6 Tips for Designing Your Unique Blog

If done correctly, a blog can be hugely successful; it can create a large following,…

2 months ago

How to Record and Transcribe a Google Hangouts Meet Video

As we all know, the current COVID-19 situation has brought the entire world to a…

2 months ago

5 Signs You Need To Hire A Website Designer

As the digital face of your business, how your website is perceived to the outside…

2 months ago

21 Chrome Extensions for Web Development

Since its introduction in 2008, Google Chrome has become the most used and the most…

2 months ago

15 cool React Admin Templates

As a react developer, building your Admin Template from scratch can be quite stressful and…

2 months ago