Algunas de las cosas que veremos a lo largo de este documento:
Login: Autenticación y cookies.
Manejo de la Sesión.
Atributo PrincipalPermission, Atributo SecureOperation, SecureActionLink y AntiForgeryToken.
Vínculo con PowerAccess.
Login: Autenticación y Cookies
Para autenticarnos, luego de validar usuario y contraseña, procederemos a crear una cookie propia de la aplicación, para almacenar ahí los datos de la sesión. Esto es necesario para que, una vez obtenida la cookie, el navegador pueda enviar al servidor los datos que lo autentican como usuario validado de la aplicación. Para ello, si espíamos en las cookies con las herramientas de desarrollador del navegador, veremos algo como esto:
En esta imagen, debemos prestar atención a cuatro cosas, por el momento:
El valor: Es el "token" que nos otorgó el servidor. Es el que nos valida como usuarios autenticados y el que nos permitirá seguir adelante en el uso de la aplicación de acuerdo a las autorizaciones que tengamos.
La duración/expiración de la sesión: En este caso dice "Sesión", es decir que su caducación no dependerá de una fecha/hora determinada sino que lo manejará el servidor de acuerdo a la validez de la sesión.
La propiedad HTTPOnly: La cual indicará que la cookie solo podrá ser manipulada a través de protocolo http. Es decir, que no podrá ser ni solicitada ni modificada por JavaScript, por ejemplo.
La propiedad Secure: Esta propiedad obligará a que la cookie sea manipulada solo bajo https. Hay que tener especial cuidado con este flag porque, si el sitio web se aloja bajo un dominio sin https, al no enviarse esta cookie, puede hacer que no funcione correctamente la aplicación.
Como datos importantes a tener en cuenta de esta forma de manejar la seguridad:
Se generan cookies, por lo que el navegador las debe tener habilitadas.
El servidor debe guardar información de cada sesión y mantenerlas en el tiempo.
No contempla el login por dispositivo, ya que fue pensado para usuarios físicos interactuando con la aplicación.
Si no tenemos cuidado con los flags de HttpOnly y Secure de las cookies, estamos más expuestos a vulnerabilidades.
Manejo de la Sesión
Respecto de este tema, no hay mucho que decir, pero es importante recalcar algunas cosas, ya que marcan una forma de trabajo que cambiará, cómo veremos con el uso de APIs.
Los aspectos más importantes a tener en cuenta son:
La sesión en este esquema, como ya dijimos, es manejada por el servidor. Es decir, es el servidor quién guardará información de cada uno de los usuarios que se autentiquen en la aplicación.
La estrategia más común (casi la única) que se utiliza bajo este esquema es que la sesión tiene un tiempo de duración. Pero no es un tiempo fijo, sino es un tiempo desde la última interacción con el servidor. Esto quiere decir que, con cada actividad del usuario que termine en una interacción con el servidor, éste último debe extender la duración de esa sesión a "x tiempo" desde esa última interacción.
Para tratar de graficar con un ejemplo: Si yo inicié sesión a las 14:00 horas, y asumiendo una sesión de 10 minutos, mi sesión será válida hasta las 14:10. Entonces:
Si yo hago una petición al servidor a las 14:11, el mismo no validará esa petición y me enviará a autenticarme nuevamente.
Si yo en vez de hacer la petición a las 14:11 la hago a las 14:09, el servidor validará mi identidad y procederá al procesamiento de esa petición. Además, extenderá la duración de mi sesión hasta las 14:19 horas.
Al estar almacenada la sesión en el servidor, por más que se cierre el navegador o se haga un "full refresh", mientras la cookie no se altere, el servidor seguirá validando esa sesión. Pero si el servidor se reinicia, ya sea a nivel SO o a nivel Servidor de Aplicaciones (Ejm: IIS, Apache, etc) , se perderán todas las sesiones, las cookies que están en los navegadores ya no contendrán un token válido (ya que el servidor almacena en memoria volátil la información de las sesiones) y se pedirá a todos los usuarios que se autentiquen nuevamente.
Atributo PrincipalPermission, Atributo SecureOperation, SecureActionLink y AntiForgeryToken
A este punto, tenemos un usuario autenticado, con una cookie generada por nosotros y con sesión válida. Ahora bien: ¿Cómo nuestro código valida esto? ¿Qué hacemos si queremos exponer un controller que sea de uso común, pra información pública y no necesitamos que valide una sesión?
Para responder estas dos preguntas, surge el Atributo Principal Permission. El mismo tiene una serie de parámetros que contemplan distintas situaciones. Nosotros usaremos uno solo. Entonces, es deber del desarrollador poner en cada uno de los controllers que deben restringir su acceso, la siguiente línea:
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
Este atributo se coloca antes de la declaración de un controlador, siempre y cuando el mismo no se desee utilizar de manera pública y que no necesite de una sesión válida.
Hasta aquí, hemos hablado de autenticación. Vamos a hablar ahora de autorización.
La autenticación se propone identificar a la entidad que interactúa con nuestra aplicación, comúnmente mediante un usuario y una contraseña.
La autorización, por su parte, trata acerca de qué recursos está autorizada a acceder una entidad.
Entonces, respecto de la autoraización surgen:
SecureOperation: debe colocarse al prinicpio de un método del controlador. Recibe como parámetro un string que identificará a la operación con la que deberá validarse al usuario identificado, para saber si tiene permiso o no. Ejemplo:
[SecureOperation("Reporte de Actas de Examen")]
public ActionResult Index()
Esto significará que si yo me autentico con el usuario "noanet" e invoco a ese método Index, la aplicación validará antes de entrar al método si yo tengo o no permisos sobre la operación "Reporte de Actas de Examen"-
SecureActionLink: Es idéntico a SecureOperation pero está pensado para front-end. Permite especificar a quién se le muestra un html determinado, validando permisos sobre una operación, de la siguiente forma:
@Html.SecureActionLink("<a class=\"btn btn-black\" id=\"btnAddSchool\" href=\"" + Url.Content("~/Students/Create") + "\">+</a>", "Alta de Alumno")
Es decir, el html que está en el primer parámetro, solo se mostrará si el usuario logueado tiene permisos sobre la operación "Alta de Alumno".
Finalmente, tenemos la herramienta del AntiForgeryToken.
Dicho Token es generado por el desarrollador, idealmente bajo algún formulario de la siguiente forma:
@Html.AntiForgeryToken()
Esto genera en nuestro html un input type="hidden" con un token que también es almacenado en memoria volátil en el servidor. Este token tiene la particularidad de que le pertenece a un único usuario (al logueado) y que es aleatorio. Sirve para evitar ataques CSRF (Cross-Site Request Forgery). Este ataque sirve para que desde otra pestaña del navegador o inclusive desde otro navegador, no aprovechen nuestra autenticación en una determinada página para generar datos o modifcarlos. Se trata de agregar un string aleatroio, asociado al usuario logueado, el cual es generado y almacenado por el servidor y enviado al cliente para que, en su próxima petición lo envíe junto con los datos del formulario.
Para que este token funcione, además de agregar el html que mencionamos recién, arriba del método que queremos proteger, debemos agregar el atributo ValidateAntiForgeryToken de la siguiente forma:
[ValidateAntiForgeryToken]
public JsonResult Create(DebitNote model)
{
De esta forma, si alguien intenta enviar un post desde otra pestaña, puede conocer la url y los parámetros que tiene que enviar, y puede llegar a valerse de nuestra autenticación. Lo que es muy poco probable que haga es conocer este token que es aleatorio, generado en el momento por el servidor y atado a la sesión.