¿Cómo implementa github.com la mitigación de CSRF?

8

He echado un vistazo a CSRF recientemente. La estrategia de mitigación recomendada es implementar la Synchronizer Token Pattern .

Cuando miras los detalles, surge la pregunta de con qué frecuencia es necesario cambiar estos tokens. De nuevo, la recomendación general es que los tokens por sesión son suficientes. Puede obtener tokens por solicitud si necesita seguridad adicional (o si tiene una situación en la que la pérdida de tokens CSRF es un problema).

Al verificar cómo los sitios grandes implementan la protección CSRF, eché un vistazo a github.com. Lo que me sorprende es que no puedo entender por qué implementaron su enfoque como lo hicieron.

Se me ocurre que usan tokens por solicitud (aún más, tokens por formulario únicos). Sin embargo, los tokens antiguos no se invalidan después de haber sido utilizados. Daré un ejemplo.

Consideremos la página de perfiles de github: enlace .

La respuesta a una solicitud GET contiene tres formularios con un authenticity_token como parámetro de entrada oculto. Si recuerdo correctamente, github está construido basado en Rails. Así que esto encaja, ya que el nombre coincide con el nombre predeterminado de mecanismo de protección Rails CSRF . Además, los tokens tienen una longitud de 64 bytes, lo que coincide con la longitud del enfoque de toques de CSRF enmascarados de Rails .

Las fichas se adjuntan a los siguientes formularios:

  • Token 1: el botón Cerrar sesión
  • Token 2: el botón Actualizar perfil
  • Token 3: el botón Guardar perfil de trabajos

Si vuelve a cargar la página, los valores de los tres tokens cambiarán.

Consideremos un POST posterior que actualice mi perfil.

  • Si envío el Token 2 previsto, se realiza la acción.
  • Si envío un token no válido, la acción no se realiza (el servidor devuelve HTTP 422).

Hasta ahora todo bien, ahora a las cosas que no entiendo. La acción también se realiza, sin error, cuando hago una de las siguientes solicitudes:

  • Envíe otro token de la página (diga Token 1 o Token 3 de arriba).
  • Presentar el token 2 nuevamente. Por lo tanto, el token antiguo no se invalida cuando se usa. Esto funciona varias veces.
  • Vuelve a cargar la página, pero envía una de las fichas antiguas.

Entonces, supongo que todo se reduce a: ¿Por qué github implementa tokens por solicitud (incluso por formulario), pero nunca los invalida / verifica que pertenecen al elemento de formulario correcto?

O tal vez estoy totalmente equivocado, y github en realidad implementa un enfoque diferente (como un patrón de token cifrado).

    
pregunta user32387 19.10.2015 - 18:09
fuente

2 respuestas

1

GitHub valida authenticity_token para implementar una protección CSRF. Tienes razón en que están utilizando un token por formulario.

Sin embargo, no estoy seguro de que el token nunca se invalide. Ha ignorado la posibilidad de que authenticity_token sea un token de vida corta que sea válido por un período de tiempo, por ejemplo, 60 minutos. [Esta cifra no es precisa, verificaré lo mismo y actualizaré la figura exacta aquí.]

Ahora, desde la perspectiva del ataque, veamos cuál es el riesgo adicional que posee un token reutilizable sobre un token anti CSRF de un solo uso.

En el momento en que se valida un token en el lado del servidor para verificar si la solicitud está falsificada, la aplicación está protegida contra CSRF. Si el token utilizado no es un token de uso único, el posible vector de ataque requiere la posesión de al menos un token válido.

¿Cuáles son las formas probables de obtener el único token anti CSRF aquí?

El atacante necesitará acceder a la memoria del navegador para robar el token, lo que lo hace extremadamente difícil y un vector de ataque casi imposible. Y también tenga en cuenta que, en GitHub, el authenticity_token es válido solo durante una sesión activa. En el momento en que cierre la sesión y vuelva a iniciar sesión, cualquier authenticity_token de la sesión anterior ya no será válido.

    
respondido por el hax 26.11.2016 - 14:34
fuente
1

Flujo de trabajo no lineal

La pregunta parece asumir un flujo de trabajo lineal, es decir, el usuario carga la página A que tiene el token A1; realiza una acción que requiere ese token; carga la página A nuevamente, esta vez con el token A2, y realiza una acción que lo requiere.

Sin embargo, es perfectamente razonable que los usuarios tengan varias páginas abiertas en la misma sesión: puede "usar un token" en una pestaña, luego cambiar a otra pestaña que se abrió hace una hora y hacer clic en un botón que envía un token que técnicamente es mucho más antiguo que el que acabas de usar. Si el token anterior hubiera sido invalidado, se vería como un error obvio desde la perspectiva del usuario.

Además, es razonable usar el botón Atrás, que puede volver a una versión en caché de la página con los tokens antiguos. Puede OBTENER un formulario con un token en particular, enviar una solicitud POST con este token, luego recordar que necesita cambiar una cosa más, presionar el botón Atrás (que muestra el formulario nuevamente sin buscar una nueva versión) y luego enviar otro POST solicite con (obviamente) el mismo token CSRF que acaba de usar. Nuevamente, este es un flujo de trabajo razonable, y debería funcionar, y la invalidación del token lo rompería.

Cierta invalidación de tokens CSRF sería razonable, pero debería ocurrir en condiciones similares a la expiración de la sesión, ya sea en el cierre de sesión explícito o en un tiempo de espera similarmente largo; no se trata simplemente de usar un token más nuevo, ya que dentro de una sola sesión es razonable que los tokens se utilicen fuera de orden y / o se vuelvan a utilizar.

    
respondido por el Peteris 26.12.2016 - 19:06
fuente

Lea otras preguntas en las etiquetas