Métodos de autenticación web explicados

En la lección de hoy vamos a comenzar con la más básica, la autenticación HTTP básica, continuaremos con las cookies y los tokens , y terminaremos con firmas y contraseñas de un solo uso. Sigue leyendo para que aprendas todo acerca de esto.

Autenticación básica HTTP

La autenticación HTTP básica es un método para que el cliente proporcione un nombre de usuario y una contraseña al realizar una solicitud.

Esta es la forma más sencilla posible de imponer el control de acceso, ya que no requiere cookies, sesiones o cualquier otra cosa. Para usar esto, el cliente debe enviar la Authorization junto con cada solicitud que realice. El nombre de usuario y la contraseña no están cifrados, pero se construyen de esta manera:

El nombre de usuario y la contraseña se concatenan en una sola cadena: username:password esta cadena está codificada con Base64

La palabra clave Basic se coloca antes de este valor codificado

Ejemplo para un usuario nombrado juan con contraseña con secreta:


curl --header "Authorization: Basic am9objpzZWNyZXQ=" my-website.com

Implementarlo también es bastante fácil en Node.js: el siguiente fragmento de código muestra cómo puedes hacer un middleware Express para hacerlo.

import basicAuth from 'basic-auth';

function unauthorized(res) {
res.set('WWW-Authenticate', 'Basic realm=Authorization Required');
return res.send(401);
};

export default function auth(req, res, next) {
const {name, pass} = basicAuth(req) || {};

if (!name || !pass) {
return unauthorized(res);
};

if (name === 'juan' && pass === 'secreta') {
return next();
}
return unauthorized(res);
};

Por supuesto, puedes hacerlo en un nivel superior, como en nginx .

Parece simple, ¿verdad? Entonces, ¿cuáles son los inconvenientes de usar la autenticación HTTP básica ?

Los contras:

  • El nombre de usuario y la contraseña se envían con cada solicitud, exponiéndolos potencialmente, incluso si se envían a través de una conexión segura conectado a SSL / TLS, si un sitio web utiliza un cifrado débil o un atacante puede romperlo,
  • Los nombres de usuario y las contraseñas se expondrán de inmediato no hay manera de cerrar la sesión del usuario usando la autenticación básica, la caducidad de las credenciales no es trivial: debe pedirle al usuario que cambie la contraseña para hacerlo.

Cookies

Cuando un servidor recibe una solicitud HTTP en la respuesta, puede enviar un encabezado Set-Cookie. El navegador lo coloca en un contenedor de cookies, y la cookie se enviará junto con cada solicitud realizada al mismo origen en el encabezado Cookie HTTP.

Para utilizar las cookies con fines de autenticación, hay algunos principios clave que se deben seguir.

Siempre use las cookies de HttpOnly

Para mitigar la posibilidad de ataques XSS, siempre use la bandera HttpOnly al configurar las cookies. De esta manera no aparecerán en document.cookies.

Siempre usa cookies firmadas

Con las cookies firmadas, un servidor puede saber si el cliente modificó una cookie.

Más adelante, todas las solicitudes utilizan las cookies establecidas para el dominio dado:

Uso de cookies de Chrome

Los contras:

  • Necesidad de hacer un esfuerzo extra para mitigar los ataques CSRF
  • Incompatibilidad con REST, ya que introduce un estado en un protocolo sin estado

Fichas

Hoy en día, JWT (JSON Web Token) está en todas partes; aunque vale la pena echarle un vistazo a los posibles problemas de seguridad.

JWT consta de tres partes:

  • Encabezado: que contiene el tipo de token y el algoritmo de hash
  • Carga útil: conteniendo las reclamaciones.
  • Firma: que puede calcularse de la siguiente manera si elige HMAC SHA256: HMACSHA256( base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)

Agregar JWT a las aplicaciones Koa es tan solo un par de líneas de código:

var koa = require('koa');
var jwt = require('koa-jwt');

var app = koa();

app.use(jwt({
secret: 'very-secret'
}));

// Middleware protegido
app.use(function *(){
// el contenido del token estará disponible en this.state.user
this.body = {
secret: '42'
};
});

Ejemplo de uso:

curl --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" my-website.com

Como los anteriores, los tokens se pueden observar también en Chrome:

Si está escribiendo API para aplicaciones móviles nativas o SPA, JWT puede ser una buena opción para ti. Una cosa a tener en cuenta: para usar JWT en el navegador, debe almacenarlo en LocalStorage o SessionStorage, lo que puede provocar ataques XSS.

Los contras:

  • Necesidad de hacer un esfuerzo extra para mitigar los ataques XSS

Firmas

Ya sea utilizando cookies o tokens, si la capa de transporte por cualquier motivo queda expuesta, sus credenciales son fáciles de acceder, y con un token o cookie el atacante puede actuar como el usuario real.

Una posible forma de resolver esto, al menos cuando hablamos de API y no del navegador, es firmar cada solicitud. ¿Cómo podemos hacerlo?

Cuando un consumidor de una API realiza una solicitud, debe firmarla, lo que significa que debe crear un hash de toda la solicitud mediante una clave privada. Para ese cálculo de hash puedes usar:

  • Método HTTP
  • Ruta de la solicitud
  • Encabezados HTTP
  • Suma de comprobación de la carga útil HTTP
  • y una clave privada para crear el hash

Para que funcione, tanto el consumidor de la API como el proveedor deben tener la misma clave privada. Una vez que tengas la firma, debes agregarla a la solicitud, ya sea en cadenas de consulta o encabezados HTTP. Además, también se debe agregar una fecha, para que pueda definir una fecha de vencimiento.

¿Por qué pasar por todos estos pasos? Porque incluso si la capa de transporte se ve comprometida, un atacante solo puede leer su tráfico, no podrá actuar como usuario, ya que el atacante no podrá firmar solicitudes, ya que la clave privada no está en su poder. La mayoría de los servicios de AWS están utilizando este tipo de autenticación.

node-http-signature se ocupa de la firma de solicitud HTTP y vale la pena consultar.

Los contras:

  • No se puede usar en el navegador / cliente, solo entre APIs

Contraseñas de un solo uso

Los algoritmos de contraseñas de un solo uso generan una contraseña de un solo uso con un secreto compartido y la hora actual o un contador:

  • Algoritmo de contraseña de un solo uso basado en el tiempo, está basado en la hora actual.
  • Algoritmo de contraseña de un solo uso basado en HMAC, está basado en un contador.

Estos métodos se utilizan en aplicaciones que aprovechan la autenticación de dos factores: un usuario ingresa el nombre de usuario y la contraseña, y tanto el servidor como el cliente generan una contraseña de un solo uso.

En Node.js, implementar esto usando notp es relativamente fácil.

Contras:

  • Con los tokens de usuario de secreto compartido (si son robados) se pueden emular
  • porque los clientes pueden ser robados, todas las aplicaciones en tiempo real tienen métodos para evitar esto, como un restablecimiento de correo electrónico que agrega vectores de ataque adicionales a la aplicación
¿Qué método de autenticación web elegir cuando?

Si solo tienes que admitir una aplicación web, las cookies o los tokens están bien. Para las cookies, piensa en XSRF, para que JWT se encargue de XSS.

Si tienes que admitir una aplicación web y un cliente móvil, usa una API que admita una autenticación basada en algún token.

Si estás creando API que se comunican entre sí, mejor usa la firma de solicitud.