Authentication with AngularJS, Session Management, and Security Issues with REST Api WS

I started developing a web application with angularJS, and I'm not sure that everything is properly protected (client and server). Security is based on a single login page, if the credentials are verified in order, my server sends a unique token with user-specific timing. All other REST api are available through this token. The application (client) looks at my ex account: https://www.example.com/home.html the user enters the credentials and receives a unique token back. This unique token is stored in the server database using AES or other secure methods; it is not stored in a clear format.

From now on, my AngluarJS application will use this token for authentication for all REST Api.

I am thinking of temporarily storing a token in a custom http cookie; basically, when the server checks the credentials, it sends back a new Ex cookie.

app-token : AIXOLQRYIlWTXOLQRYI3XOLQXOLQRYIRYIFD0T 

The cookie has the secure and HTTP only flags set. The Http protocol directly manages and saves a new cookie. Successive requests will contain a cookie with a new parameter, without having to manage it and store it using javascript; with each request, the server cancels the token and generates a new one and sends it to the client → prevent repeated attacks with one token.

When a client receives an unauthorized 401 HTTP status response from any REST Api, the angular controller clears all cookies and redirects the user to the login page.

Should I consider other aspects? Is it better to store the token in a new cookie or in localStorage? Any tips on how to create a unique strong token?

Edit (improvements):

  • I decided to use the HMAC-SHA256 as a session token generator with 20 minutes confidence. I generate a random 32-byte GUID, attach a timestamp, and compute HASH-SHA256, providing a key of 40 bytes. It is completely impossible to get collisions, since the token expiration is very minimal.
  • A cookie will have domain attributes and ways to increase security.
  • Multiple logins are allowed.
+66
angularjs authentication rest cookies
Jan 01 '14 at 15:59
source share
4 answers

If you are talking to the server via https, you have no problem with replay attacks.

My suggestion was to use server security technology. For example, JavaEE has a built-in login mechanism, declarative role-based resource protection (REST endpoints), etc. All of them are managed using a set of cookies, and you do not need to worry about storage and expiration. Check what the server / infrastructure already gives you.

If you plan to extend your API to a wider audience (not specifically to a browser-based user interface) or other types of clients (such as a mobile application), consider adopting OAuth.

At the top of my head, Angular has the following security features (will add more as they appear):

CSRF / XSRF Attacks

Angular supports the CSRF engine. Check out the $http docs . Server-side support required.

Content Security Policy

Angular has an expression evaluation mode that is compatible with the more rigorous JavaScript scripts that apply when CSP is enabled. Check out the ng-csp docs .

Strict contextual escaping

Use Angular's new $sce (1.2+) function to simplify your interface against XSS attacks, etc. It is a little less convenient, but safer. Check out the docs here .

+54
Jan 16 '14 at 19:21
source share
— -

This is client-side protection that you can implement in regular versions of Angular. I tried and checked this. (Please find my article here: - https://www.intellewings.com/post/authorizationonangularroutes ) In addition to client-side route security, you also need to protect server-side access. Security on the client side helps to avoid an extra trip to the server. However, if someone tricks the browser, server-side security should be able to reject unauthorized access.

Hope this helps!

Step 1. Define global variables in the application module

-define application roles

  var roles = { superUser: 0, admin: 1, user: 2 }; 

-define route for unauthorized access to the application

  var routeForUnauthorizedAccess = '/SomeAngularRouteForUnauthorizedAccess'; 

Step 2. Define a service for authorization

 appModule.factory('authorizationService', function ($resource, $q, $rootScope, $location) { return { // We would cache the permission for the session, to avoid roundtrip to server for subsequent requests permissionModel: { permission: {}, isPermissionLoaded: false }, permissionCheck: function (roleCollection) { // we will return a promise . var deferred = $q.defer(); //this is just to keep a pointer to parent scope from within promise scope. var parentPointer = this; //Checking if permisison object(list of roles for logged in user) is already filled from service if (this.permissionModel.isPermissionLoaded) { //Check if the current user has required role to access the route this.getPermission(this.permissionModel, roleCollection, deferred); } else { //if permission is not obtained yet, we will get it from server. // 'api/permissionService' is the path of server web service , used for this example. $resource('/api/permissionService').get().$promise.then(function (response) { //when server service responds then we will fill the permission object parentPointer.permissionModel.permission = response; //Indicator is set to true that permission object is filled and can be re-used for subsequent route request for the session of the user parentPointer.permissionModel.isPermissionLoaded = true; //Check if the current user has required role to access the route parentPointer.getPermission(parentPointer.permissionModel, roleCollection, deferred); } ); } return deferred.promise; }, //Method to check if the current user has required role to access the route //'permissionModel' has permission information obtained from server for current user //'roleCollection' is the list of roles which are authorized to access route //'deferred' is the object through which we shall resolve promise getPermission: function (permissionModel, roleCollection, deferred) { var ifPermissionPassed = false; angular.forEach(roleCollection, function (role) { switch (role) { case roles.superUser: if (permissionModel.permission.isSuperUser) { ifPermissionPassed = true; } break; case roles.admin: if (permissionModel.permission.isAdministrator) { ifPermissionPassed = true; } break; case roles.user: if (permissionModel.permission.isUser) { ifPermissionPassed = true; } break; default: ifPermissionPassed = false; } }); if (!ifPermissionPassed) { //If user does not have required access, we will route the user to unauthorized access page $location.path(routeForUnauthorizedAccess); //As there could be some delay when location change event happens, we will keep a watch on $locationChangeSuccess event // and would resolve promise when this event occurs. $rootScope.$on('$locationChangeSuccess', function (next, current) { deferred.resolve(); }); } else { deferred.resolve(); } } }; }); 

Step 3. Using security in routing. Allows you to use all of our harsh words made so far to protect routes

 var appModule = angular.module("appModule", ['ngRoute', 'ngResource']) .config(function ($routeProvider, $locationProvider) { $routeProvider .when('/superUserSpecificRoute', { templateUrl: '/templates/superUser.html',//path of the view/template of route caseInsensitiveMatch: true, controller: 'superUserController',//angular controller which would be used for the route resolve: {//Here we would use all the hardwork we have done above and make call to the authorization Service //resolve is a great feature in angular, which ensures that a route controller(in this case superUserController ) is invoked for a route only after the promises mentioned under it are resolved. permission: function(authorizationService, $route) { return authorizationService.permissionCheck([roles.superUser]); }, } }) .when('/userSpecificRoute', { templateUrl: '/templates/user.html', caseInsensitiveMatch: true, controller: 'userController', resolve: { permission: function (authorizationService, $route) { return authorizationService.permissionCheck([roles.user]); }, } }) .when('/adminSpecificRoute', { templateUrl: '/templates/admin.html', caseInsensitiveMatch: true, controller: 'adminController', resolve: { permission: function(authorizationService, $route) { return authorizationService.permissionCheck([roles.admin]); }, } }) .when('/adminSuperUserSpecificRoute', { templateUrl: '/templates/adminSuperUser.html', caseInsensitiveMatch: true, controller: 'adminSuperUserController', resolve: { permission: function(authorizationService, $route) { return authorizationService.permissionCheck([roles.admin,roles.superUser]); }, } }) }); 
+9
Aug 24 '14 at 21:45
source share
 app/js/app.js ------------- 'use strict'; // Declare app level module which depends on filters, and services var app= angular.module('myApp', ['ngRoute']); app.config(['$routeProvider', function($routeProvider) { $routeProvider.when('/login', {templateUrl: 'partials/login.html', controller: 'loginCtrl'}); $routeProvider.when('/home', {templateUrl: 'partials/home.html', controller: 'homeCtrl'}); $routeProvider.otherwise({redirectTo: '/login'}); }]); app.run(function($rootScope, $location, loginService){ var routespermission=['/home']; //route that require login $rootScope.$on('$routeChangeStart', function(){ if( routespermission.indexOf($location.path()) !=-1) { var connected=loginService.islogged(); connected.then(function(msg){ if(!msg.data) $location.path('/login'); }); } }); }); app/js/controller/loginCtrl.js ------------------------------- 'use strict'; app.controller('loginCtrl', ['$scope','loginService', function ($scope,loginService) { $scope.msgtxt=''; $scope.login=function(data){ loginService.login(data,$scope); //call login service }; }]); app/js/directives/loginDrc.js ----------------------------- 'use strict'; app.directive('loginDirective',function(){ return{ templateUrl:'partials/tpl/login.tpl.html' } }); app/js/services/sessionService.js --------------------------------- 'use strict'; app.factory('sessionService', ['$http', function($http){ return{ set:function(key,value){ return sessionStorage.setItem(key,value); }, get:function(key){ return sessionStorage.getItem(key); }, destroy:function(key){ $http.post('data/destroy_session.php'); return sessionStorage.removeItem(key); } }; }]) app/js/services/loginService ---------------------------- 'use strict'; app.factory('loginService',function($http, $location, sessionService){ return{ login:function(data,scope){ var $promise=$http.post('data/user.php',data); //send data to user.php $promise.then(function(msg){ var uid=msg.data; if(uid){ //scope.msgtxt='Correct information'; sessionService.set('uid',uid); $location.path('/home'); } else { scope.msgtxt='incorrect information'; $location.path('/login'); } }); }, logout:function(){ sessionService.destroy('uid'); $location.path('/login'); }, islogged:function(){ var $checkSessionServer=$http.post('data/check_session.php'); return $checkSessionServer; /* if(sessionService.get('user')) return true; else return false; */ } } }); index.html ---------- <!doctype html> <html lang="en" ng-app="myApp"> <head> <meta charset="utf-8"> <title>My AngularJS App</title> <link rel="stylesheet" href="css/app.css"/> </head> <body> <div ng-view></div> <!-- In production use: <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> --> <script src="lib/angular/angular.js"></script> <script src="lib/angular/angular-route.js"></script> <script src="js/app.js"></script> <script src="js/directives/loginDrc.js"></script> <script src="js/controllers/loginCtrl.js"></script> <script src="js/controllers/homeCtrl.js"></script> <script src="js/services/loginService.js"></script> <script src="js/services/sessionService.js"></script> </body> </html> 
+2
Jun 22 '16 at 4:46
source share

First, there is no short or just one answer to what you asked. In addition to what has already been given, let me add one more thing. At the enterprise level, there are four main components:

  1. UI
  2. User Authentication Server - here you check the user credentials and generate the necessary cookies so that the user can move on through the user interface. If this step is not performed, the user immediately stops. This server has nothing to do with API token generation & this is also necessary for non-API based systems. One example is Google Authentication.

Extension: Siteminder Authentication

SiteMinder Cookies, Their Use, Content and Security

Creating a Java authentication server for Chatkit

  1. API Token Server - this server generates API tokens based on cookies created in step # 2, i.e. you send cookies to the server and get a token
  2. .API - you use the token generated in step 3 to make API calls.

It is better if you deploy & control these four components independently for a better scale. for example, in this article, they confused authentication & token generation at one endpoint & this is not good - Microservices with Spring Boot - Authentication with JWT (Part 3)

According to your record, it looks like you wrote the second component & three yourself - usually people use several ready-made tools for this, such as CA SiteMinder - How CA Siteminder Works - Basics

Any tips on how to create a unique strong token?

I would advise you to follow a standardized path for better maintainability & safety, i.e. You choose the JWT format. JSON Web Token Authentication Scheme (JWT)

Your token will be signed & encrypted, so you will also need an encryption key server & mechanism to rotate these keys at regular intervals.

JSON Web Tokens - How to securely store a key?

What is the difference between JWT and manually encrypting some json using AES?

A certification authority employee has posted a comprehensive PDF manual on this community portal to help you understand the overall progress.

Sample code / application for using the JWT token REST API

Your API code will need to get the encryption key and decrypt & decode the token to authenticate the token. If the token is damaged or missing, you must mark it as such. There are libraries for this.

Is it better to store the token inside a new cookie or in LocalStorage?

local storage if the user interface & API are in different domains & Cookies if on the same domain.

Should the JWT be stored in localStorage or cookie?

Cross Domain Cookies

Application security also depends on the deployment model and the part that you did not specify in your question. Sometimes developers can leave the same flaws in their code as SQL injection :)

What to do if JWT is stolen?

+1
Mar 23 '19 at 8:16
source share



All Articles