Angular.JS: Acing Security with $sce

Hi, reader! Hope you’re having a great week so far! On our last blog post, we saw Backbone.JS, a JavaScript framework, which provides structure to our client side code. Seeing Backbone was very refreshing especially after coming from the Underscore blogpost which focused more on utility functions and dealt less with structure.

Now for this blog post, we’ll be leaning on to AngularJS, it’s $sce service in particular. Often in coding projects, we get to encounter strings which contain HTML elements that should be rendered as html elements themselves. For example: markdowns, user generated html strings, etc.

And often, the frameworks we use don’t dispaly them as it should be (for security), rather, as simple strings. That is why we can use their sanitizing methods (such as html_safe for Ruby on Rails) by which we declare that we trust the string and we want it displayed as HTML (whatever the contents are).

Here’s a Rails example:

We have two strings with two versions each, one that is raw and another one that is declared safe with html_safe.

Screen Shot 2016-01-21 at 11.31.49 PM.png

When we load the page containing these:

We see that our JS script was ran once (alert flashed),

Screen Shot 2016-01-21 at 11.32.02 PM.png

And also a string containing our string was printed. Similar to the strong tag, in the html_safe version, <strong> was evaluated and led to bold letters.

Screen Shot 2016-01-21 at 11.31.41 PM.png

Now, that we have already got the hang of it, let’s now focus on Angular JS and its $sce service.

ng-bind-html

Similar to Rails’ html_safe that we saw a while ago, AngularJS has a similar version, the ng-bind-html directive. And let’s see an example.

Here we have a simple AngularJS application with a textarea with myHtml assigned as the ng-model. And then two divs attached to the myHtml ng-model as well. These divs are listening to any value changes with the model and reflects them accordingly.

What sets these two divs apart is that one is bounded via the simple ng-bind while the other one is bound by ng-bind-html.

Screen Shot 2016-01-22 at 12.05.00 AM.png

Let us see the difference:

Screen Shot 2016-01-22 at 12.04.52 AM.png

For the div that binded to myHtml using  the simple ng-bind, the value was just printed as a string while for the second div which was bound using ng-bind-html, the html was evaluated and the string in bold letters was shown.

Buuuut, why won’t we want something like this all the time? It is because we can’t always trust user input or interpolated for that matter. What if some bad guy injects malicious snippets of code into a seemingly clean html text like the following:

Screen Shot 2016-01-22 at 12.35.02 AM.png

As we see above, the line seems clean and safe – just a string with a series of characters and one (cute) emoticon. But then when we (accidentally or intentionally) hover on it, KABOOM:

Screen Shot 2016-01-22 at 12.34.03 AM.png

JK. It’s not really just a string, it actually has a onmouseover event attached to it. Our actual string was:

Screen Shot 2016-01-22 at 12.33.56 AM.png

Lucky for us that the hidden JavaScript is just an alert message but what if it was something more serious (i.e. XSS).

This has indeed some security concerns! So to solve, angular actually has the $sce service, short for Strict Contextual Escaping, which ensures and

requires that bindings in certain contexts to result in a value that is marked as safe to use for that context

If you’re using Angular version 1.2 or higher and you tried copying the above snippets of code, you may notice that it results to an error:

Screen Shot 2016-01-22 at 12.55.59 AM.png

And this is because the $sce is already loaded and enabled by default in AngularJS versions 1.2 and higher. And as we mentioned earlier, $sce ensures and requires that binding result to a value that is marked as safe. (And we haven’t explicitly marked our input to be safe or trusted).

To demo the above data bindings without explicitly marking our html values as safe, I just disabled the $sce in my AngularJS version 1.4.1 to demonstrate how the ng-bind-html have behaved before $sce was loaded by default.

Note: Disabling the $sce module is highly discouraged as disabling it is like stripping away one security layer from your app.

Btw, if you’re curious and want to know how to disable $sce, you just need to set the enabled attribute of the $sceProvider to false in the config section of your module:

Screen Shot 2016-01-22 at 1.17.09 AM.png

$sce, $sceProvider, $trustAs*

So now, let’s work on the default behaviour of AngularJS (1.2 onwards) – with $sce enabled. So either we just set enabled to true or just erase the config part completely as it defaults to true.

So now going back to the error above, let’s try to fix it. With $sce enabled we are saying that the value should be sanitized and marked as safe first. So what we can do is use Angular’s trustAs* methods.

Here we are saying that we explicitly trust the contents and it is safe to display it as it is with whatever the original value is.

Screen Shot 2016-01-22 at 2.01.51 AM.png

Screen Shot 2016-01-22 at 2.02.46 AM.png

The behaviour is similar to how our app a while ago behaved when $sce is disabled. For this one, our explicit consent was asked for first before the HTML was rendered.

So since we declared that we trust the HTML to be safe, it is rendered as it is with the JavaScript script intact and enabled. So upon hovering, we got the message:

Screen Shot 2016-01-22 at 8.50.39 PM.png

What we can take from here is that explicitly trusted html/strings/values already bypasses any checks (but note that the CORS rules from your browser still apply and might impose stricter rules).

There are still many variations to the trustAs* method. There is trustAsJs, trustAsCss among others but they are used more or less the same way and what just differs is the type of value that they wrap.

ngSanitize

In case you were wondering how to clean and sanitize data, AngularJS provides the ngSanitize module which, when loaded, automatically cleans / sanitizes your HTML string, already getting rid of hiding JS scripts, etc.

To use ngSanitize:

  1. Include angular-sanitize.js to your page, you may get it via CDN or save it locally. You may see the instructions here.
  2. Load ngSanitize into your Angular app:
    Screen Shot 2016-01-22 at 1.13.04 AM.png
  3. And that’s it! ngSanitize is now loaded and ready to clean your bound values.

Say we have the following:

Screen Shot 2016-01-22 at 1.08.44 AM.png

Screen Shot 2016-01-22 at 9.13.28 PM.png

Hovering on “Anybody here?” doesn’t yield any alerts. Due to ngSanitize’s automatic cleaning, even if we didn’t explicitly parse clean our string, the sneaky script was automatically weeded out. We also did not need to use trustAsHtml on our controllers as once our string have passed ngSanitize’s secure parsing methods, our string is already marked as trusted and safe for display.

So there, we saw a few security features that AngularJS provides! Hope you’ll find them useful anywhere you see fit to further improve your app’s security. 🙂

Thank you so much for reading!

Wishing you a great and lovely weekend ahead,
Adelen

References:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s