nodejs example bearer basada autenticacion angularjs rest authentication cookies angularjs-authentication

angularjs - example - bearer token nodejs



Autenticación con AngularJS, administración de sesión y problemas de seguridad con REST Api WS (3)

Empecé a desarrollar una aplicación web con angularJS y no estoy seguro de que todo esté bien protegido (cliente y servidor). La seguridad se basa en una sola página de inicio de sesión. Si las credenciales se comprueban correctamente, mi servidor devuelve un token único con validez temporal personalizada. El resto de la API REST son accesibles a través de este token. La aplicación (cliente) busca mi punto de entrada ex: https://www.example.com/home.html credenciales de inserción de usuario y recibe un token único. Este token único se almacena en la base de datos del servidor con AES u otras técnicas seguras, no se almacena en formato claro.

A partir de ahora, mi aplicación AngluarJS usará este token para autenticarse en todo REST Api expuesto.

Estoy pensando en almacenar temporalmente el token en una cookie http personalizada; básicamente, cuando el servidor verifica las credenciales, envía una nueva cookie Ex.

app-token : AIXOLQRYIlWTXOLQRYI3XOLQXOLQRYIRYIFD0T

La cookie tiene los indicadores secure y HTTP solo activados. El protocolo Http administra directamente la nueva cookie y la almacena. Las solicitudes sucesivas presentarán la cookie con el nuevo parámetro, sin la necesidad de administrarlo y almacenarlo con javascript; en cada solicitud, el servidor invalida el token y genera uno nuevo y lo envía de vuelta al cliente -> prevenir ataques de repetición con un solo token.

Cuando el cliente recibe una respuesta no autorizada de estado HTTP 401 desde cualquier Api REST, el controlador angular limpia todas las cookies y redirige al usuario a la página de inicio de sesión.

¿Debería considerar otros aspectos? ¿Es mejor almacenar el token dentro de una nueva cookie o localStorage? ¿Algún consejo sobre cómo generar un token sólido único?

Editar (mejoras):

  • Decidí usar HMAC-SHA256 como generador de tokens de sesión, con 20 minutos de validez. Genero un GUID aleatorio de 32 bytes, adjunto una marca de tiempo y calculo el HASH-SHA256 proporcionando una clave de 40 bytes. Es bastante imposible obtener colisiones ya que la validez del token es bastante mínima.
  • Cookie tendrá atributos de dominio y ruta para aumentar la seguridad.
  • No se permiten múltiples inicios de sesión.

Esta es la seguridad del lado del cliente que puede implementar en versiones angulares regulares. He intentado y probado esto. (Encuentre mi artículo aquí: - http://www.codeproject.com/Tips/811782/AngularJS-Routing-Security ) Además de la seguridad de la ruta del lado del cliente, también necesita asegurar el acceso al servidor. La seguridad del lado del cliente ayuda a evitar viajes adicionales al servidor. Sin embargo, si alguien engaña al navegador, la seguridad del lado del servidor del servidor debería poder rechazar el acceso no autorizado.

¡Espero que esto ayude!

Paso 1: defina variables globales en el módulo de la aplicación

-definir roles para la aplicación

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

-Definir ruta para acceso no autorizado para la aplicación

var routeForUnauthorizedAccess = ''/SomeAngularRouteForUnauthorizedAccess'';

Paso 2: define el servicio para la autorización

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(); } } }; });

Paso 3: Use la seguridad en el enrutamiento: usemos toda nuestra hardword hecha hasta ahora, para asegurar las rutas

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]); }, } }) });


Si hablas con el servidor a través de https, no tienes ningún problema con los ataques de repetición.

Mi sugerencia sería aprovechar la tecnología de seguridad de su servidor. Por ejemplo, JavaEE tiene un mecanismo de inicio de sesión listo para usar, protección declarativa basada en roles de los recursos (sus puntos finales REST) ​​etc. Todos estos se administran con un conjunto de cookies y no tiene que preocuparse por el almacenamiento y el almacenamiento. vencimiento. Mira lo que tu servidor / framework ya te da.

Si planea exponer su API a un público más amplio (no específicamente a la interfaz de usuario basada en el navegador que sirve) u otros tipos de clientes (por ejemplo, la aplicación móvil), considere la adopción de OAuth.

Angular tiene las siguientes características de seguridad (agregará más a medida que salgan):

Ataques CSRF / XSRF

Angular admite un mecanismo de salida para la protección CSRF . Consulte $http docs . Se necesita soporte en el lado del servidor.

Política de seguridad de contenido

Angular tiene un modo de evaluación de expresión que es compatible con tiempos de ejecución de JavaScript más estrictos que se aplican cuando CSP está habilitado. Consulte ng-csp docs .

Estricto Escape Contextual

Use la nueva función $sce sce de Angular (1.2+) para fortalecer su UI contra ataques XSS, etc. Es un poco menos conveniente pero más seguro. Mira los documentos here .


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>