¿Es este un buen enfoque para asegurar mi API REST?

3

Mi aplicación consta de una API de back-end nodejs pero también estoy desarrollando una implementación de "referencia" de un cliente JavaScript, que es un backbone SPA .

En primer lugar; La API solo acepta solicitudes HTTPS, en caso de que una solicitud HTTP llegue al servidor, la ignora por completo y también (dependiendo de la configuración del cliente) invalida la contraseña proporcionada en esa solicitud insegura.

Mi servidor no tiene estado y solo uso autenticación básica HTTP (S) . Proporciono dos formas de autenticar una solicitud:

1- Enviando credenciales en el encabezado Authentication: base64('Basic ' + user:password)
2- Enviar una solicitud autenticada utilizando el método 1 a GET /users/current que devuelve un token que es una cadena cifrada * que contiene: username + '|' + timeOfTokenExpiration . El cliente luego envía solo el encabezado Authentication: base64('Token ' + username:returnedToken) a partir de entonces.

* El cifrado se realiza con el algoritmo aes-256-ctr de OpenSSL, y la clave es el hash de contraseña del usuario

El método 1 se puede usar para una comunicación directa de servidor a servidor, pero no es adecuado para un cliente de JavaScript, ya que el usuario tendría que insertar sus credenciales en cada solicitud, lo que no es factible .

El almacenamiento de las credenciales de usuario en el almacenamiento local del navegador solucionaría este problema pero mantendría al usuario registrado indefinidamente, creando otra posible amenaza para la seguridad. Tampoco estoy seguro de lo seguro que es almacenar las credenciales en texto sin cifrar en la memoria del navegador .

Al utilizar método 2 , el cliente JavaScript enviaría solo una solicitud autenticada y luego almacenaría las credenciales cifradas en el almacenamiento local, después de un período de tiempo determinado tiene que volver a validar las credenciales del usuario, ya que eventualmente caducará y El servidor ya no aceptará solicitudes de ese token.

En el lado del servidor, compruebo la autenticidad de una solicitud del método 2 recuperando el hash de la contraseña del usuario y tratando de descifrarlo. Después del descifrado, compruebo si decryptedString.split('|')[0] === username .

¿Es este un enfoque seguro / bueno?

    
pregunta Renato Gama 07.12.2014 - 23:01
fuente

1 respuesta

3

Hay un problema con tu método 2: si utilizas el hash del usuario como clave de cifrado para el token, y lo único que se verifica en el servidor es si el token se descifra (no se realiza ninguna otra validación en el token) - entonces quien tenga el hash del usuario puede autenticarse como ese usuario. Esto anula cualquier protección * otorgada por el hash de la contraseña del usuario, también puede almacenarlo como texto sin formato ...

Sugeriría no molestarse en cifrar el token (ya que no contiene datos confidenciales), solo firmándolo con un secreto conocido solo por el servidor, y verificando que la firma sea válida cuando el usuario intenta autenticarse utilizando el método 2. Tenga en cuenta que por "firma" me refiero a una firma digital que usa una clave privada conocida solo por el servidor, o un HMAC que usa un secreto similar. Recordar no almacenar este secreto en la propia base de datos, sino en un módulo de hardware, solo en memoria o, si es necesario, en un archivo de configuración.

* Para ser justos, al menos la contraseña seguirá estando protegida: solo su sistema será vulnerable, otros sistemas , donde el usuario ha reutilizado esa contraseña no se verá afectada negativamente.

    
respondido por el mgibsonbr 04.03.2015 - 02:32
fuente

Lea otras preguntas en las etiquetas