Video Summary and Transcription
Bienvenido a mi sesión sobre cómo evitar CSRF con Remix. Remix ayuda a proteger contra CSRF al pensar en acciones en términos de elementos de formulario HTML. Para evitar CSRF con Remix, establece el mismo atributo de sitio en las cookies y considera usar un token además del atributo. El enfoque basado en tokens implica generar un token único por sesión y formulario, transmitirlo con el formulario, enviarlo de vuelta cuando el usuario envía el formulario y validar de forma segura en el lado del servidor.
1. Introducción a CSRF y Remix
Bienvenido a mi sesión sobre cómo evitar CSRF con Remix. CSRF significa Cross-Site Request Forgery, donde el atacante engaña al usuario para que acceda a una URL y realice una acción utilizando su sesión existente. Incluso si se utiliza el método POST, se puede lograr una explotación con un iframe y una URL separada. Remix ayuda a proteger contra CSRF al pensar en las acciones en términos de elementos de formulario HTML. Para evitar CSRF con Remix, establezca el mismo atributo de sitio en las cookies y considere utilizar un token además del atributo.
Hola y bienvenido a mi sesión sobre cómo evitar CSRF con Remix. Esta es una charla rápida, así que vamos a pasar por esto de manera bastante rápida. Comencemos hablando de qué es CSRF. Como la mayoría de las explotaciones de seguridad, tiene un acrónimo y significa Cross-Site Request Forgery. Y en este escenario, básicamente el atacante engaña al usuario para que acceda a la URL y luego esta URL realizará una acción utilizando su sesión existente.
Un ejemplo simple, o tal vez el peor ejemplo, es una imagen con una URL y esa URL realiza una acción. Antes de que digas que quieres escribir código como este, he visto esto en aplicaciones que he auditado, y obviamente lo primero que el usuario está haciendo mal aquí es que está utilizando GET para realizar alguna acción. Pero igualmente, este tipo de explotación se puede lograr incluso si se utiliza POST. Y lo hacemos teniendo un iframe con una altura y ancho ocultos, y eso incrusta una URL separada. Y en esa URL tenemos el formulario, el POST a ese endpoint, y tenemos una función onload que lo envía tan pronto como se carga el formulario.
Así que hablemos un poco de Remix. Remix te hace pensar en las acciones en términos de los bloques de construcción de la web, que son los elementos de formulario HTML. Y si has estado construyendo aplicaciones con JavaScript, probablemente hayas estado usando cosas como Fetch o Axios, y en estos escenarios, por supuesto, te protege. A menos que, por supuesto, estés usando access, allow origin, ya sabes, star, y estás permitiendo que las credenciales pasen. Y en ese caso, estás en la misma situación. Así que porque estamos enviando formularios nuevamente a través de datos de formulario multiparte, necesitamos pensar en Cross-Site Request Forgery.
Así que veamos un ejemplo simple de formulario Remix. Aquí tenemos un formulario primitivo con un campo de texto y un botón de enviar. Tenemos algún tipo de cargador para verificar que el usuario tenga una sesión autenticada porque Cross-Site Request Forgery requiere que estén conectados. Ya sabes, estás realizando una acción utilizando su sesión existente que no pretendían hacer. Y por lo tanto, no vamos a entrar en los detalles aquí, pero sí, el cargador se asegura de que el usuario tenga una sesión. Luego tenemos una acción en nuestro componente que hace alguna escritura en la base de datos o similar. Algo que realiza alguna acción que, ya sabes, no se puede revertir. Entonces, ¿cómo evitas Cross-Site Request Forgery con Remix en este escenario? Bueno, lo primero que debes hacer es establecer el mismo atributo de sitio en tus cookies. Puedes establecerlo como lax, lo que significa que el navegador solo enviará las cookies si es una solicitud GET que proviene de otro dominio. O puedes establecerlo como strict, lo que significa que no enviará ninguna cookie para ninguna solicitud que se origine desde otro dominio. Por lo tanto, es posible que debas verificar si estás utilizando algún tipo de flujo de autenticación que redirige a otros sitios para determinar cuál es el más apropiado para tu sitio. Pero desafortunadamente, según OWASP, esto no es suficiente y no debemos reemplazarlo con un token. Y la razón principal de eso es que solo el 93% de los navegadores admiten el atributo de mismo sitio en esta etapa. Casi estamos allí.
2. Generación y Validación de Tokens CSRF
El enfoque basado en tokens implica un proceso de cuatro pasos: generar un token único por sesión y formulario, transmitirlo con el formulario, enviarlo de vuelta cuando el usuario envía el formulario y validarlo de forma segura en el lado del servidor. Para generar el token, se generan claves aleatorias seguras, incluyendo una sal de hash y una clave privada. El token se transmite con el cargador y se devuelve en los datos del cargador, que se pueden acceder en el formulario. La validación se realiza regenerando el token y comparándolo con la versión enviada. Si no coinciden, se genera un error.
Tu aplicación puede tener más dependiendo de la mezcla de navegadores de tus usuarios. Por lo tanto, el enfoque basado en tokens se llama comúnmente el patrón de token sincronizado y básicamente es un proceso de cuatro pasos.
Lo primero que debes hacer es generar un token único por sesión, por formulario. Debes transmitirlo con el formulario. Debes enviarlo de vuelta cuando el usuario envía el formulario y luego debes validarlo de forma segura en el lado del servidor.
Así que comenzamos generando algunas claves aleatorias seguras. Generamos una sal de hash y esto es algo que no debes almacenar en tu database. Debe estar en disco o en variables de entorno para que si tu database se ve comprometida incluso entonces la sal de hash no se filtre. También debes tener una clave privada y ambas puedes generarlas usando el paquete de bytes aleatorios de crypto.
Entonces, el primer paso es generar una semilla aleatoria única por sesión y lo hacemos comprobando si la semilla ya existe en la sesión. Si existe, la utilizamos. Si no existe, generamos una nueva semilla utilizando nuevamente la función de bytes aleatorios y la almacenamos en la sesión. Luego necesitamos generar un token único por sesión e identificador y en este escenario el identificador sería algo único para ese formulario u operación y esto evita que el mismo token sea válido para dos operaciones diferentes y evita la reutilización de tokens.
Para hacer esto, tomamos ese hash, por lo que tomamos nuestra clave privada, también tomamos la semilla y combinamos las tres y creamos un digest HMAC de eso, que es básicamente un hash. Nos da un token único agradable. Tenemos que transmitir ese token con el cargador. Lo primero que hacemos es generar el token y devolverlo en nuestros datos del cargador y eso significa que luego podemos obtenerlo en nuestro formulario usando los datos de la ruta. Así obtenemos nuestro token CSRF de allí y lo transmitimos en el formulario en nuestro campo oculto.
Luego necesitamos validar el código, por lo que si escribimos una pequeña función de utilidad para validar lo regenerará el token basado en el identificador único y la sesión y luego comparará los dos usando equals seguro en tiempo contra la versión que se envió con el formulario. Usamos equals seguro en tiempo aquí para evitar ataques de tiempo.
Entonces, ¿cómo usamos esta función de utilidad? En nuestra acción, simplemente podemos llamar a validate CRSF token usando el valor del formulario enviado y si los dos no coinciden, lanzamos un error. Así es como se realiza la validación de CSRF en Remix. Si tienes alguna pregunta, por favor contáctame a través del servidor de Discord de GitHub para esta conferencia o puedes enviarme un mensaje en Twitter. Gracias.
Comments