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).