¿Por qué es común colocar tokens de prevención CSRF en las cookies?

Resuelto metamatt asked hace 10 años • 4 respuestas

Estoy tratando de comprender todo el problema con CSRF y las formas apropiadas de prevenirlo. (Recursos que he leído, entiendo y con los que estoy de acuerdo: Hoja de trucos de prevención de CSRF de OWASP , Preguntas sobre CSRF )

Según tengo entendido, la vulnerabilidad en torno a CSRF se debe a la suposición de que (desde el punto de vista del servidor web) una cookie de sesión válida en una solicitud HTTP entrante refleja los deseos de un usuario autenticado. Pero todas las cookies para el dominio de origen se adjuntan mágicamente a la solicitud del navegador, por lo que realmente todo lo que el servidor puede inferir de la presencia de una cookie de sesión válida en una solicitud es que la solicitud proviene de un navegador que tiene una sesión autenticada; No puede asumir nada más sobre el código que se ejecuta en ese navegador, o si realmente refleja los deseos del usuario. La forma de evitar esto es incluir información de autenticación adicional (el "token CSRF") en la solicitud, realizada por algún medio distinto del manejo automático de cookies del navegador. Entonces, en términos generales, la cookie de sesión autentica al usuario/navegador y el token CSRF autentica el código que se ejecuta en el navegador.

En pocas palabras, si está utilizando una cookie de sesión para autenticar a los usuarios de su aplicación web, también debe agregar un token CSRF a cada respuesta y requerir un token CSRF coincidente en cada solicitud (mutante). Luego, el token CSRF realiza un viaje de ida y vuelta desde el servidor al navegador y de regreso al servidor, demostrando al servidor que la página que realiza la solicitud está aprobada (incluso generada por) ese servidor.

Pasemos a mi pregunta, que trata sobre el método de transporte específico utilizado para ese token CSRF en ese viaje de ida y vuelta.

Parece común (por ejemplo, en AngularJS , Django , Rails ) enviar el token CSRF del servidor al cliente como una cookie (es decir, en un encabezado Set-Cookie), y luego hacer que Javascript en el cliente lo extraiga de la cookie y lo adjunte. como un encabezado XSRF-TOKEN separado para enviarlo de regreso al servidor.

(Un método alternativo es el recomendado, por ejemplo, por Express , donde el token CSRF generado por el servidor se incluye en el cuerpo de la respuesta mediante la expansión de la plantilla del lado del servidor, adjunto directamente al código/marcado que lo devolverá al servidor, por ejemplo como una entrada de formulario oculta. Ese ejemplo es una forma más web 1.0 de hacer las cosas, pero se generalizaría bien a un cliente con más JS).

¿Por qué es tan común utilizar Set-Cookie como transporte descendente para el token CSRF? ¿Por qué es una buena idea? Me imagino que los autores de todos estos marcos consideraron sus opciones cuidadosamente y no se equivocaron. Pero a primera vista, usar cookies para solucionar lo que es esencialmente una limitación de diseño de las cookies parece una tontería. De hecho, si utilizara cookies como transporte de ida y vuelta (Set-Cookie: encabezado descendente para que el servidor le indique al navegador el token CSRF, y Cookie: encabezado ascendente para que el navegador lo devuelva al servidor), reintroduciría la vulnerabilidad que están tratando de arreglar.

Me doy cuenta de que los marcos anteriores no utilizan cookies durante todo el recorrido de ida y vuelta del token CSRF; usan Set-Cookie en sentido descendente, luego algo más (por ejemplo, un encabezado X-CSRF-Token) en sentido ascendente, y esto cierra la vulnerabilidad. Pero incluso utilizar Set-Cookie como transporte descendente es potencialmente engañoso y peligroso; el navegador ahora adjuntará el token CSRF a cada solicitud, incluidas las solicitudes XSRF maliciosas genuinas; en el mejor de los casos, eso hace que la solicitud sea más grande de lo necesario y, en el peor, algún fragmento de código de servidor bien intencionado pero equivocado podría intentar usarlo, lo que sería realmente malo. Y además, dado que el destinatario real del token CSRF es Javascript del lado del cliente, eso significa que esta cookie no se puede proteger solo con http. Entonces, enviar el token CSRF en sentido descendente en un encabezado Set-Cookie me parece bastante subóptimo.

metamatt avatar Dec 11 '13 03:12 metamatt
Aceptado

Una buena razón, que ya ha mencionado, es que una vez que se recibe la cookie CSRF, está disponible para su uso en toda la aplicación en el script del cliente para su uso tanto en formularios normales como en POST AJAX. Esto tendrá sentido en una aplicación con mucho JavaScript, como la empleada por AngularJS (el uso de AngularJS no requiere que la aplicación sea una aplicación de una sola página, por lo que sería útil cuando el estado debe fluir entre diferentes solicitudes de página donde el valor CSRF normalmente no puede persistir en el navegador).

Considere los siguientes escenarios y procesos en una aplicación típica para conocer algunos pros y contras de cada enfoque que describa. Estos se basan en el patrón de token del sincronizador .

Solicitar enfoque corporal

  1. El usuario inicia sesión exitosamente.
  2. El servidor emite una cookie de autenticación.
  3. El usuario hace clic para navegar a un formulario.
  4. Si aún no se ha generado para esta sesión, el servidor genera un token CSRF, lo almacena en la sesión del usuario y lo envía a un campo oculto.
  5. El usuario envía el formulario.
  6. El servidor comprueba que el campo oculto coincida con el token almacenado de la sesión.

Ventajas:

  • Sencillo de implementar.
  • Funciona con AJAX.
  • Funciona con formularios.
  • En realidad, la cookie puede ser solo HTTP .

Desventajas:

  • Todos los formularios deben generar el campo oculto en HTML.
  • Cualquier POST AJAX también debe incluir el valor.
  • La página debe saber de antemano que requiere el token CSRF para poder incluirlo en el contenido de la página, de modo que todas las páginas deben contener el valor del token en alguna parte, lo que podría llevar mucho tiempo implementarlo en un sitio grande.

Encabezado HTTP personalizado (descendente)

  1. El usuario inicia sesión exitosamente.
  2. El servidor emite una cookie de autenticación.
  3. El usuario hace clic para navegar a un formulario.
  4. La página se carga en el navegador y luego se realiza una solicitud AJAX para recuperar el token CSRF.
  5. El servidor genera un token CSRF (si aún no se ha generado para la sesión), lo almacena en la sesión del usuario y lo envía a un encabezado.
  6. El usuario envía el formulario (el token se envía a través de un campo oculto).
  7. El servidor comprueba que el campo oculto coincida con el token almacenado de la sesión.

Ventajas:

  • Funciona con AJAX.
  • La cookie puede ser solo HTTP .

Desventajas:

  • No funciona sin una solicitud AJAX para obtener el valor del encabezado.
  • Todos los formularios deben tener el valor agregado a su HTML de forma dinámica.
  • Cualquier POST AJAX también debe incluir el valor.
  • La página debe realizar primero una solicitud AJAX para obtener el token CSRF, por lo que significará un viaje de ida y vuelta adicional cada vez.
  • También podría haber simplemente enviado el token a la página que guardaría la solicitud adicional.

Encabezado HTTP personalizado (ascendente)

  1. El usuario inicia sesión exitosamente.
  2. El servidor emite una cookie de autenticación.
  3. El usuario hace clic para navegar a un formulario.
  4. Si aún no se ha generado para esta sesión, el servidor genera un token CSRF, lo almacena en la sesión del usuario y lo muestra en algún lugar del contenido de la página.
  5. El usuario envía el formulario a través de AJAX (el token se envía a través del encabezado).
  6. El servidor comprueba que el encabezado personalizado coincida con el token almacenado de la sesión.

Ventajas:

  • Funciona con AJAX.
  • La cookie puede ser solo HTTP .

Desventajas:

  • No funciona con formularios.
  • Todos los POST AJAX deben incluir el encabezado.

Encabezado HTTP personalizado (ascendente y descendente)

  1. El usuario inicia sesión exitosamente.
  2. El servidor emite una cookie de autenticación.
  3. El usuario hace clic para navegar a un formulario.
  4. La página se carga en el navegador y luego se realiza una solicitud AJAX para recuperar el token CSRF.
  5. El servidor genera un token CSRF (si aún no se ha generado para la sesión), lo almacena en la sesión del usuario y lo envía a un encabezado.
  6. El usuario envía el formulario a través de AJAX (el token se envía a través del encabezado).
  7. El servidor comprueba que el encabezado personalizado coincida con el token almacenado de la sesión.

Ventajas:

  • Funciona con AJAX.
  • La cookie puede ser solo HTTP .

Desventajas:

  • No funciona con formularios.
  • Todos los POST AJAX también deben incluir el valor.
  • La página debe realizar primero una solicitud AJAX para obtener el token CRSF, por lo que significará un viaje de ida y vuelta adicional cada vez.

Conjunto de cookies

  1. El usuario inicia sesión exitosamente.
  2. El servidor emite una cookie de autenticación.
  3. El usuario hace clic para navegar a un formulario.
  4. El servidor genera un token CSRF, lo almacena en la sesión del usuario y lo envía a una cookie.
  5. El usuario envía el formulario a través de AJAX o mediante formulario HTML.
  6. El servidor comprueba que el encabezado personalizado (o campo de formulario oculto) coincida con el token almacenado de la sesión.
  7. La cookie está disponible en el navegador para su uso en solicitudes AJAX y de formulario adicionales sin solicitudes adicionales al servidor para recuperar el token CSRF.

Ventajas:

  • Sencillo de implementar.
  • Funciona con AJAX.
  • Funciona con formularios.
  • No necesariamente requiere una solicitud AJAX para obtener el valor de la cookie. Cualquier solicitud HTTP puede recuperarlo y se puede agregar a todos los formularios/solicitudes AJAX a través de JavaScript.
  • Una vez que se ha recuperado el token CSRF, como se almacena en una cookie, el valor se puede reutilizar sin solicitudes adicionales.

Desventajas:

  • Todos los formularios deben tener el valor agregado a su HTML de forma dinámica.
  • Cualquier POST AJAX también debe incluir el valor.
  • La cookie se enviará para cada solicitud (es decir, todos los GET para imágenes, CSS, JS, etc., que no participan en el proceso CSRF), lo que aumenta el tamaño de la solicitud.
  • La cookie no puede ser solo HTTP .

Por lo tanto, el enfoque de cookies es bastante dinámico y ofrece una manera fácil de recuperar el valor de la cookie (cualquier solicitud HTTP) y usarlo (JS puede agregar el valor a cualquier formulario automáticamente y se puede emplear en solicitudes AJAX ya sea como encabezado o como valor del formulario). Una vez que se ha recibido el token CSRF para la sesión, no es necesario regenerarlo ya que un atacante que emplea un exploit CSRF no tiene ningún método para recuperar este token. Si un usuario malintencionado intenta leer el token CSRF del usuario mediante cualquiera de los métodos anteriores, la Política del mismo origen lo impedirá . Si un usuario malintencionado intenta recuperar el token CSRF del lado del servidor (por ejemplo, a través de curl), este token no se asociará a la misma cuenta de usuario, ya que la cookie de sesión de autenticación de la víctima faltará en la solicitud (sería del atacante; por lo tanto, ganó). No estará asociado al lado del servidor con la sesión de la víctima).

Además del patrón de token de sincronización, también existe el método de prevención CSRF de cookie de envío doble , que por supuesto utiliza cookies para almacenar un tipo de token CSRF. Esto es más fácil de implementar ya que no requiere ningún estado del lado del servidor para el token CSRF. De hecho, el token CSRF podría ser la cookie de autenticación estándar cuando se utiliza este método, y este valor se envía a través de cookies como es habitual con la solicitud, pero el valor también se repite en un campo o encabezado oculto, que un atacante no puede replicar. no pueden leer el valor en primer lugar. Sin embargo, se recomendaría elegir otra cookie que no sea la cookie de autenticación para que la cookie de autenticación pueda protegerse marcándola como HttpOnly. Esta es otra razón común por la que encontraría prevención CSRF utilizando un método basado en cookies.

SilverlightFox avatar Dec 11 '2013 11:12 SilverlightFox

El uso de una cookie para proporcionar el token CSRF al cliente no permite un ataque exitoso porque el atacante no puede leer el valor de la cookie y, por lo tanto, no puede colocarla donde la validación CSRF del lado del servidor requiere que esté.

El atacante podrá generar una solicitud al servidor con la cookie del token de autenticación y la cookie CSRF en los encabezados de la solicitud. Pero el servidor no busca el token CSRF como una cookie en los encabezados de la solicitud, sino que busca en la carga útil de la solicitud. E incluso si el atacante sabe dónde colocar el token CSRF en la carga útil, tendría que leer su valor para colocarlo allí. Pero la política de origen cruzado del navegador impide leer cualquier valor de cookie del sitio web de destino.

La misma lógica no se aplica a la cookie del token de autenticación, porque el servidor la espera en los encabezados de la solicitud y el atacante no tiene que hacer nada especial para colocarla allí.

Tongfa avatar Oct 07 '2016 23:10 Tongfa