Asegurando una aplicación de página única de JavaScript con un backend RESTful

65

Actualmente estoy en el proceso de construir un SPA SPA y he estado investigando cómo protegerlo. Actualmente hay una API REST con la que se está interactuando completamente a través de AJAX. También tenemos clientes móviles que interactúan con esta API, y actualmente solo es compatible con la autenticación básica HTTP a través de SSL. La aplicación JavaScript también se comunicará exclusivamente a través de SSL, pero BASIC Auth no la cortará, ya que eso implicaría almacenar la contraseña (o un derivado de ella) en el cliente. Por último, la aplicación SPA será JavaScript y HTML puros, servidos en el mismo servidor que la API RESTful, pero sin ningún marco del lado del servidor.

Objetivos :

  • No hay un marco del lado del servidor para el cliente javascript (es solo otro cliente).
  • Mantenga la apatridia de la API REST, por las razones típicas (escalabilidad, tolerancia a fallos, implementación simplificada, etc.)
  • Cualquier estado debe ser mantenido por el cliente. Para los propósitos de esta pregunta, esto significa las credenciales de inicio de sesión.
  • El estado de inicio de sesión mantenido por el cliente debe ser seguro y resistente al secuestro de sesión y ataques similares.

Lo que he encontrado se basa en mi investigación de OAuth y esquemas similares (Amazon, etc.).

  1. El usuario iniciará sesión con HTTP POST sobre SSL.
  2. El servidor calculará un hash de la siguiente manera:

    HMAC (key, userId + ":" + ipAddress + ":" + userAgent + ":" + todaysDateInMilliseconds)

  3. Este token se devolverá al cliente y se suministrará con cada solicitud posterior en lugar del nombre de usuario y la contraseña. Lo más probable es que se almacene en localStorage o en una cookie.

¿Esto es seguro? Mi motivación para elegir userId, ipAddress, todaysDateInMilleseconds es crear un token que sea válido solo hoy, pero que no requiera una búsqueda en la base de datos para cada solicitud Y que sea seguro almacenarlo en el cliente. No puedo confiar en que la clave no se comprimirá, por lo tanto, la inclusión de la dirección IP en un intento de evitar el secuestro de la sesión.

Permítame incluir el siguiente enlace de una publicación relacionada en StackExchange porque creo que aborda muchos de los problemas que intento resolver: REST y los Id. de sesión sin estado

Después de la respuesta inicial aquí, he decidido usar solo los dos primeros octetos de la dirección IP para manejar mejor a los clientes que están detrás de proxies y móviles. Todavía no es perfecto, pero es una compensación por alguna seguridad adicional.

    
pregunta Jon Wingfield 01.09.2012 - 21:46
fuente

3 respuestas

29

El servicio ofrecido por el token es que el servidor de alguna manera reconocerá el token como uno de los suyos. ¿Cómo puede el servidor validar un token basado en HMAC? Al volver a calcularlo, utilice su clave HAMC secreta y los datos sobre los que opera HMAC . Si desea que su token se calcule sobre el ID de usuario, la contraseña, el IP y la fecha, entonces el servidor debe conocer toda esa información. Sin embargo, no desea que su servidor almacene la contraseña y el cliente no la devolverá con cada solicitud. ¿Cómo puede funcionar tu sistema, entonces?

La idea básica, sin embargo, es sólida:

  • Los usuarios "inician sesión" por cualquier forma que usted considere adecuada.
  • Tras dicho inicio de sesión, el servidor envía un valor de cookie, que se enviará con cada solicitud posterior (eso es lo que hacen las cookies).
  • La cookie contiene el ID de usuario, la fecha en que se emitió y un valor m = HMAC (K, userID || date || IP) .
  • Cuando el servidor recibe una solicitud, valida la cookie: el ID de usuario y la fecha son de la propia cookie, la IP de origen se obtiene de la capa del servidor web y el servidor puede volver a calcular el valor m para verificar que coincida con la almacenada en la cookie.

Puede reemplazar toda la cookie con un ID de sesión aleatorio, si el servidor tiene algún espacio de almacenamiento (temporal). De hecho, el servidor podría recordar la asignación de un ID de sesión aleatorio a la información específica del usuario (como su nombre y dirección IP); el ID de sesión anterior puede caducar automáticamente, por lo que el espacio de almacenamiento no crece indefinidamente. La cookie descrita anteriormente es solo una forma de descargar el almacenamiento en el propio cliente.

Nota: el uso de la dirección IP puede implicar algunos problemas prácticos. Algunos clientes están detrás de proxies, incluso proxies de carga equilibrada, por lo que no solo es posible que la dirección IP del cliente esté "oculta" (desde el servidor, se ve la dirección del proxy, no la dirección del cliente) sino que la dirección IP que obtiene del servidor podría moverse de forma errática (si dos solicitudes sucesivas del cliente han pasado por distintos servidores proxy en una granja de servidores proxy)

    
respondido por el Thomas Pornin 01.09.2012 - 22:12
fuente
8

Hay una solución mucho más simple:

Use SSL en todo el sitio, y luego use el seguimiento de sesión estándar de su marco.

Eso es todo lo que necesitas hacer.

Con más detalle, el usuario inicia sesión inicialmente proporcionando su nombre de usuario y contraseña; se envía al servidor, quien puede verificar su validez. Si la autenticación es exitosa, el código de su servidor establece un indicador en el estado de la sesión, recordando que el usuario se ha autenticado exitosamente y recordando el nombre de usuario del usuario. Todas las solicitudes posteriores se realizarán en la misma sesión, por lo que puede autenticarlas fácilmente y permitirles continuar.

(Aún más detalles: cada vez que recibe una solicitud, verifica el estado de la sesión para ver si el usuario se ha autenticado correctamente y está autorizado para realizar esta acción. Si es así, permite la solicitud y realiza la acción; en caso negativo , redirige al usuario a una página de inicio de sesión o presenta otro mensaje de error.)

Tenga en cuenta que esto cumple con todos sus requisitos. No requiere una búsqueda de base de datos en cada solicitud. Es compatible con una API RESTful. Es compatible con una aplicación de una sola página. No necesita codificar nada sofisticado: solo usa el soporte existente de su marco para las sesiones (por lo general, usa una cookie de sesión con un ID de sesión único y algún mecanismo para almacenar el estado en el lado del servidor asociado con ese ID de sesión) .

Como parte del uso de SSL en todo el sitio, debe establecer el indicador seguro en su cookie de ID de sesión, para protegerlo de las escuchas ilegales (esto asegurará que nunca se enviará a través de HTTP). También debe habilitar HSTS para decirle al navegador que siempre use SSL en su sitio. Busque en este sitio para obtener más información sobre cómo implementar SSL en todo el sitio.

No debe confiar en que la dirección IP del cliente sea estática. Puede cambiar, por ejemplo, si el cliente es móvil y se mueve de una red inalámbrica a otra. Por lo tanto, es mejor evitar el uso de la dirección IP del cliente para cualquier cosa.

    
respondido por el D.W. 02.09.2012 - 01:50
fuente
2

Consulte esta publicación Uso de OAuth2 en la aplicación web HTML5 . La respuesta de @jandersen proporciona una buena explicación sobre el uso del flujo de contraseña del propietario del recurso en aplicaciones de una sola página. En cualquier caso, el flujo preferido para estas aplicaciones debería ser la subvención implícita . De hecho, la respuesta de @jandersen en la publicación a la que se hace referencia es sobre cómo ajustar las credenciales de la contraseña del propietario del recurso para que actúen como algo cercano a la concesión implícita.

    
respondido por el Daniel Cerecedo 07.03.2014 - 10:46
fuente

Lea otras preguntas en las etiquetas