• Sign up for newsletter
  • Login

AngularJS and forms security & design

AngularJS and forms security & design

Author: Javier Rossetti, software developer @ edgescan™ - July 2015

Overview

Rich internet applications make use of the powerful features that new web browsers come equipped with. The web has come a long way since the dull, stateless server content generated HTML pages of the 90's. Today it is possible to interact with almost any webpage, thus opening a miryad of possibilities to the user and to malicious users alike.

Javascript has come to play a major role in web development, from the old days when it was merely used to manipulate the DOM (Document object model) via HTML and XML to todays powerful JS frameworks taking advantage of the much lighter JSON (JavaScript Object Notation) to send and receive data to and from servers.

Here at edgescan™ our JS framework of choice is AngularJS. Angular is pretty cool in the sense that it allows developers to create dynamic web applications by creating reusable components such as services, directives and factories; these components can be injected into the different parts of a web application, thus helping developers to adhere to the all important DRY (Don't Repeat Yourself) principle.

AngularJS adheres to the MVC design pattern (Model, View, Controller) where the model relates to the data that comes from and is sent to an API. The view comprises the HTML and related directives for DOM manipulation. The controller handles all the business logic and is the nexus between models and views.

Forms

Forms always are a contentious topic in web development. Not only from a design point of view but from a security one too. One of the most important considerations when designing and coding forms is that any effort to enforce client side security upon forms can be easily bypassed either by disabling JS in the browser or by manipulating requests and responses.

Also any attempt to blacklist words or symbols from being input into a form is futile.

From this standpoint it is very clear that the responsibility for securing user input should rest at server side level. Unfortunately users can not be trusted and all user inputs must be validated and sanitized at server side.

Angular comes alive in the browser and as such it can be turned off, meaning a malicious user can still gain access to our db or server if server side measures are not put in place.

Having discussed security in the context of server side and client side, we can then focus in making our forms as user friendly as possible, by ensuring our forms are functional, short (as short as the demand for data allows!) and keep users in the loop as to what is happening both during the fill in process and upon submission.

What to look for

Looking at the below example form for creating a user:

                        
                        
<form class="form" name="userCreate">
  <div class="col-lg-3">
    <div class="form-group" >
        <label><span class="glyphicon glyphicon-user"></span> User  Name</label>
        <input type="text" class="form-control" ng-model="username" name="username" placeholder="Enter name" required autofocus="true">
    </div>
  </div>
  <div class="col-lg-3">
    <div class="form-group">
      <label><span class="glyphicon glyphicon-envelope"></span>   Email</label>
      <input type="email" name="email" class="form-control" ng-model="email" placeholder="Enter email" required>
    </div>
  </div>
  <div class="col-lg-3">
    <div class="form-group">
      <label><span class="glyphicon glyphicon-earphone"></span>   Phone Number</label>
      <input type="text" class="form-control" ng-model="phone_number" name="phone_number" placeholder="Enter  phone number" >
    </div>
  </div>
  <div class="col-lg-3">
    <div class="col-lg-6 col-sm-6 col-xs-6">
      <button type="submit" class="btn btn-success btn-sm"> Create User</button>
    </div>
  </div>
</form>
                        
                    
                    

Resulting in this beautiful form:

client create form

Validation in action!

It is very clear there are two fields in the above form that need to be validated to ensure consistency in the information users can input: the email and phone number fields.

For this, Angular provides us with native form validation directives to help us along the way. The available helpers are:

                        
<input
  [ng-model="string"]
  [name="string"]
  [required="string"]
  [ng-required="boolean"]
  [ng-minlength="number"]
  [ng-maxlength="number"]
  [ng-pattern="string"]
  [ng-change="string"]
  [ng-trim="boolean"]>
...
</input>
                        
                    

Therefore, if we wish to ensure a user will only enter numbers in the phone number field or a valid email address in the corresponding field we could do the following:

                        
<div class="col-lg-3">
  <div class="form-group" ng-class="{ 'has-error' : userCreate.email.$invalid && ! userCreate.email.$pristine }">
    <label><span class="glyphicon glyphicon-envelope"></span> Email</label>
    <input type="email" name="email" class="form-control" ng-model="email" ng-pattern="/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-  z]{2})?)$/i">
    <p ng-show="userCreate.email.$invalid && !userCreate.email.$pristine" class="help-block">Enter a valid email.</p> <!-- Email validation message -->
  </div>
</div>
<div class="col-lg-3">
  <div class="form-group" ng-class="{ 'has-error' : userCreate.phone_number.$invalid && !userCreate.phone_number.$pristine }">
    <label><span class="glyphicon glyphicon-earphone"></span> Phone Number</label>
    <input type="text" class="form-control" ng-model="phone_number" name="phone_number" ng-pattern="/^\d*(?:\.\d{1,2})?$/">
    <p ng-show="userCreate.phone_number.$invalid && !userCreate.phone_number.$pristine" class="help-block"><span class="glyphicon glyphicon-info-sign" tooltip="Use numbers only" tooltip-placement="bottom"></span> Enter a valid phone number</p>
  </div>
</div>
                        
                    

Wow! That looks like a lot of code! However it is necessary if we want to:

  1. ensure some sort of consistency to the inputs we accept in our applicaton.
  2. help keep the user informed as to what is happening.

The second point is a very interesting one as any type of front end validation must always be accompanied by an error message so as to let the user know what is happening both during form completion and upon submission, as suggested by Jacob Nielsen's 10 heuristics for user interface design:

"Visibility of system status: The system should always keep users informed about what is going on, through appropriate feedback within reasonable time."

Let's take a closer look at the code, the email field looks like this:

                        
<div class="form-group" ng-class="{ 'has-error' : userCreate.email.$invalid && ! userCreate.email.$pristine }">
  <label><span class="glyphicon glyphicon-envelope medium-size-glyphicon"></span>   Email</label>
  <input type="email" name="email" class="form-control" ng-model="email" ng-pattern="/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-  z]{2})?)$/i">
  <p ng-show="userCreate.email.$invalid && !userCreate.email.$pristine" class="help-  block">Enter a valid email.</p> <!-- Email validation message -->
</div>
                        
                    

The magic happens at the ng-pattern, as we make use of Angular's native service to include a regular expression (regex) to try and identify the input as a valid email address. Regex can be very complex, the above regex will provide us with the minumum necessary filter to ensure the email address entered is of the correct format, that is including a '.' (dot) and a @ symbol, Whether the email address is real or not, well we can't really check that and we have to leave it to our user's good conscience!.

There are two more important bits related to usability:

                        ng-class="{ 'has-error' : userCreate.email.$invalid && ! userCreate.email.$pristine }"
                    

the ng-class helper allows us to create a condition to check

  • a) if the email address is valid according to the regex
    userCreate.email.$invalid
  • b) if any value has been input into the field
    userCreate.email.$pristine

Where

                        
<p ng-show="userCreate.email.$invalid && !userCreate.email.$pristine" class="help-block">Enter a valid email.</p>
                        
                    

Will be triggered due to the ng-show helper that gets executed if the email address is invalid, prompting a message to the user "Enter a valid email."

Here is the validation in action:

Form validation on show

Conclusion

In the same way we have incorporated client side validation to the email field, we can take the same approach with any type of input field, always remembering that client side validation should be related to usability principles rather than security. Any security concerns should be handled at server side level.

edgescan™ can help you detect security loopholes in your code base and help you remediate and mitigate the risks of such security concerns.

edgescan, your SaaS digital security radar