Protegiendo contra CSRF, JWT, dominio cruzado

0

Tengo una aplicación pesada frontend con una api de descanso en node.js. La aplicación y el backend están en diferentes hosts. Además, se puede acceder a la aplicación con http y https. La razón por la cual se trata de contenido mixto: los usuarios de la aplicación cargan sus propios sitios web en iframes y, si un sitio web es http, no funcionará, los https rojos rotos en el mejor de los casos, no se cargarán en el peor de los casos. Bastante irónico que algo que se supone que mejora la seguridad web, me obliga a permitir el uso de conexiones no seguras. Pero ese no es el punto. Entonces, digamos que tengo mi interfaz en http (s): //app.mydomain.com y backend en enlace

Y quiero hacerlo lo más seguro posible, teniendo en cuenta que mis usuarios a veces usarán conexiones inseguras. Sé que no puedo protegerme de la manipulación, pero al menos puedo proteger el token de autenticación. Así que uso JWT. También quiero que me recuerden la funcionalidad. localStorage / sessionStorage permitiría que se leyera el token en una página http insegura, por lo que estaba pensando en configurar una cookie para enlace en el servidor. De esta manera, la interfaz nunca puede leer el token debido a CORS. Y me saltearía todas estas cosas de token de actualización. Habría solo una ficha para ser usada para todo. Por lo tanto, si un usuario inicia sesión, el servidor configurará la cookie del token y la configurará para que caduque cuando finalice la sesión del navegador, el token se configurará para que caduque en 1 día. Si el usuario lo marca, recuérdeme, la cookie se establecerá durante un año y el token caducará en un año. Ahora me gustaría preguntarte si es una forma segura de hacerlo. ¿Estoy pensando correcto?

Otra cosa obviamente es CSRF. Estaba pensando solo en revisar el remitente y dejarlo así, pero escuché que podría bloquear a los usuarios legítimos detrás de los proxies que eliminan al remitente de la solicitud. Así que estaba pensando en usar JWT como nonces. Básicamente, en el inicio, cuando el usuario inicia sesión / se autentica, el servidor devuelve un token nuevo y luego el token se almacena en la memoria del cliente y se envía con cada solicitud al servidor para su verificación.

Aquí hay un resumen del proceso:

the frontend is at http(s)://app.mydomain.com
the server is at https://api.mydomain.com

0. make an ajax call to check if the user is logged in
1. send username and password to log in
2. the server sets the cookie at https://api.mydomain.com containing the auth token
    cookie is set to expire when browser session ends, token is set to expire in 1 day
    if remember me: both cookie and token is set to expire in 1 year
3. the server also generates a different token to serve as a nonce and returns it
4. the app stores the nonce token in memory and uses it for every call

If the user is logged in, skip to step 3.

¿Qué piensas? ¿Es seguro?

    
pregunta Maciej Krawczyk 28.05.2017 - 13:32
fuente

1 respuesta

1

En general, no hay nada malo con la estrategia de autenticación y anti-CSRF descrita. La implementación incorrecta de cualquier parte podría, por supuesto, exponer el riesgo, pero la estrategia por sí sola parece estar bien.

Hay algunas áreas de preocupación que no son ideales, la más importante que ya identificó: admitir el uso no cifrado de HTTP. Como bien señalaste, esto expone un riesgo significativo para el hombre en el medio. Además del riesgo inherente para los visitantes o usuarios que eligen no usar la comunicación cifrada con SSL, pero también generalmente expone un mayor riesgo de ataques de supresión de SSL contra los usuarios que pretenden usar SSL. Algo que podría considerar aquí es hacer que una opción solo SSL esté disponible en el nivel del usuario (o de la organización del usuario, si corresponde). Los detalles de la implementación dependerían de la pila, pero si está usando algo como Express o Koa, podría tener una pieza de middleware que valide que las solicitudes HTTP están permitidas antes de devolver una respuesta. En los casos en los que no están permitidos, puede responder con un redireccionamiento 302 a la ruta HTTPS.

Las principales ventajas que puedo ver para usar una cookie en comparación con el almacenamiento local en este caso son las siguientes:

  1. La bandera HTTPOnly mitiga el riesgo de robo de token a través de scripts entre sitios (XSS). Sin embargo, esta no sería la única preocupación si tiene fallas de XSS, ya que la explotación exitosa aún podría emitir solicitudes de la sesión comprometida.
  2. Si determina si la autenticación se realiza inicialmente a través de SSL (HTTPS), puede agregar dinámicamente la marca de seguridad a la cookie cuando la emita, de modo que la eliminación de SSL expone un poco menos de riesgo ya que el token no se incluiría durante todo el tiempo. La autenticación fue segura en primer lugar. Dudaría en llamar a esta defensa infalible contra la eliminación de SSL, pero es una manera fácil de agregar un poco de defensa en profundidad.
  3. Puede que me esté perdiendo una forma, ya que debo admitir que apenas he usado la API de almacenamiento local, pero creo que necesitarías ubicar el almacenamiento local en todo el dominio, lo que significa que anotherapp.mydomain.com (de acuerdo con su ejemplo) es vulnerable, podría comprometer su almacenamiento local que contiene su token. Con la cookie, puede acceder a api.mydomain.com y usar encabezados CORS bastante restrictivos, como access-control-allow-origin: app.mydomain.com con access-control-allow-credentials también.

No me queda claro si lo que estás colocando en los iframes tiene la intención de interactuar de alguna manera con tu contenido, algo contra lo que seguramente te advertiría. En un caso ideal, podría estipular que todo el contenido incrustado tiene un certificado SSL válido, y simplemente usar HTTPS en todo momento. Sin eso, simplemente no va a tener defensas lo suficientemente sólidas como para tener una confianza razonable contra los ataques de intermediarios.

    
respondido por el user18519 28.05.2017 - 20:18
fuente

Lea otras preguntas en las etiquetas