06 Nov, 2014

Security Challenge, Universal Studios, and Authorization in AngularJS

by Anand Vemuri

Ever since I was young, I think I have always been afraid of getting on roller coasters. Something about the notion of willingly subjecting myself to steep vertical drops while clinging onto a seatbelt for dear life never quite tickled my fancy. Of course, as luck would have it, most of my friends are roller coaster enthusiasts who thrill on the adrenaline rush of zooming through gravity-defying loop-de-loops…. And so, by majority rule, I found myself casually strolling through Universal Studios in Orlando, Florida, for a recent get together.

As we stood in line for one of the rides, I couldn’t help but wonder what was preventing someone from simply jumping to the front. Naturally, the inner tech nerd in me came out and I started to analyze the security mechanism they had implemented in order to prevent sneaky people like me from skipping the line.

Typically, for rides at Universal Studios, there are two lines: one for people with season passes and one for normal visitors. The normal visitor wait time is anywhere from 45 minutes to 3 hours depending on the time of day, whereas the season pass visitor wait time is less than 15 minutes. So what is stopping you from simply jumping into the express line? There is a security guard at the beginning of the line who checks to make sure every person has a special ticket before entering the express line. There is another security guard at the middle of the line who checks to make sure you are in the right line and gives you another ticket corresponding to your level of access. This is the ticket that you eventually give before boarding the ride.

This method of offering a role-specific token allows for role validation at the end of the line, ensuring that even if someone is able to bypass the security guard in the front of the line, they are immediately caught if they try to access the ride. Interestingly enough, this is exactly the same idea that is implemented in user authentication systems in web applications. Unfortunately, many developers seem to forget about the backend validation involved and rely mainly on client-side validation.

AngularJS is a new open source web application framework maintained by Google, and it is a very powerful tool for creating single-page web applications. For anyone trying to build a secure web application, determining how to handle authentication and authorization is typically the first major security question. As a standard practice, it is usually recommended that authentication processing occurs on the server side, as the client is very easily manipulated. However, the deceptive complexity of AngularJS lends itself to developers making some very poor decisions regarding security.

In his very popular article titled, “Techniques for authentication in AngularJS applications,” Gert Hengeveld discusses several strategies for developing authentication and access control paradigms. While this article is surely well-intentioned, there seem to be a few places in which the security of the authentication mechanism appears to be compromised. For example, the following snippet of code is highlighted in order to suggest a possible method for restricting route access:

While this is a valiant attempt at explicitly defining the permissions of this view, the problem is that this configuration is exposed on the client side. Simply playing around with a client-side JavaScript debugger such as Firebug can allow a user to define his or her own userRole.

That being said, Hengeveld does acknowledge this:

“There’s nothing preventing the user from tampering with that code to gain ‘access’ to certain views and interface elements. All we can really do is visibility control.”He then proceeds to show how one can use angular directives in order to show or hide different div elements:

However, this is a client-side security measure, too. Using similar methods to the ones discussed above, a malicious hacker can easily gain access to anything on the page.

By the nature of Angular being a single-page application framework, the notion of visibility control is heavily discussed, and rather than trying to prevent users from seeing privileged HTML elements, developers try to prevent the leakage of sensitive information on these pages. In the event that a hacker is able to access a view that he or she does not have permission to see, at least sensitive data is not leaked.

Frederik Nakstad’s blog post, “ UI-Router in angular-client-side-auth,” offers a particularly interesting insight into this issue, as he has developed a sample MEAN stack application with multiple access levels. He also acknowledges the issues of client-side tampering in his post:

“The routing policy we’re ‘enforcing’ client-side is very easy to get around using Chrome Developer Tools or Firebug. The technique I’m describing is used as a way of tailoring your views and giving a better user experience, but malicious users can still change their user role and get access to client-side routes that should be restricted to them. This is not a problem as long as any sensitive data is accessed via your server-side API, and the proper authentication/authorization strategy is implemented there.”Indeed, Nakstad seems to be on the same page regarding minimizing sensitive data visibility. Here is a step-by-step demonstration of what could happen if the server is not properly secured. For demonstration’s sake, we will be hacking on sample code written in the MEAN stack ( https://github.com/avemuri57/ClientSideDataLeakage_Insecure).

We begin by accessing the home page:

So far, nothing stands out as a glaring security hazard. Upon inspection of the source code for the page, we notice that there’s a tab in the navigation bar that is hidden:

There is a hidden admin tab that is visible to users with admin privileges. The angular router, which is exposed to the client (appRoutes.js), shows us which controller is associated with each view:

In our case, we notice that the MainController is responsible for the home page. After inspecting the MainController, we notice that the following line of code sets the isAdmin flag on the client side:

We can easily circumvent this by setting a break point at this line and inserting our own custom JavaScript:

Upon page refresh, we now see the hidden Administration tab:

And with very little effort, we are able to access sensitive data.

Clearly, this is very insecure and could potentially lead to critical data leaks. The proper way to protect the data is to set up the authentication similar to the validation that Universal Studios has in place for their lines. The client side can be considered to be the security guard in the front of the line. While he or she does a decent job ensuring that the typical user goes into the right line, it’s very easy to create a diversion and sneak into the express line. Without the guard in the middle of the line issuing a token to ensure that privileged users are in the right line, any user can walk straight into the ride without any questions being asked.

In order to prevent this from happening in web applications, the server (represented by the back end of the line) needs to have some way of ensuring that the person sending a request to access sensitive information has permission to do so. This validation needs to happen independent of the client.

With this being said, I’d like to pose a challenge to all the developers out there reading this. I have provided a link with the github repo for the sample vulnerable application used in this post. How would you go about fixing it to make sure that sensitive data can’t be leaked? I will be discussing best practices in future posts and highlighting insightful and creative user solutions.

All the best!

References: