Cómo proteger aplicaciones de Node.js contra ataques CSRF
Victor Ikechukwu
17 de octubre de 2023
0 minutos de lecturaUn ataque de falsificación de petición entre sitios (CSRF) es una vulnerabilidad de seguridad que aprovecha la confianza entre un navegador web y un sitio legítimo. Los atacantes astutos manipulan los navegadores para que ejecuten acciones maliciosas en sitios donde los usuarios se autentican e inician sesión. A menudo, estos ataques comienzan cuando los usuarios hacen clic en un enlace de un correo electrónico engañoso o llegan a un sitio web comprometido, sin saber que hay lógica ejecutándose en segundo plano.
El impacto de los ataques CSRF exitosos puede ir desde pérdidas financieras y daños a la reputación de personas y empresas hasta cuentas de usuario comprometidas, transacciones no autorizadas e incluso responsabilidades legales. A medida que los ataques CSRF evolucionan y se vuelven más sofisticados, los desarrolladores web y las organizaciones deben implementar contramedidas sólidas para proteger la integridad de sus aplicaciones web.
En este artículo veremos cómo funcionan los ataques CSRF en las aplicaciones de Node.js y cómo protegernos. Revisaremos ejemplos del mundo real, con pasos prácticos y fragmentos de código, métodos para probar las protecciones y prácticas recomendadas para proteger las aplicaciones de Node.js contra ataques CSRF.
También ofrecemos una lección práctica y gratuita sobre CSRF en Snyk Learn, por si quieres empezar directamente con una lección.
Cómo funcionan los ataques CSRF
Los ataques CSRF aprovechan la confianza que las aplicaciones web depositan en las sesiones de usuarios autenticados. Al engañar a los usuarios para que realicen acciones involuntarias, los atacantes pueden manipular o divulgar datos sensibles sin que lo sepan. Antes de aprender a proteger las aplicaciones de Node.js contra estas amenazas, repasemos cómo funcionan estos ataques y cuáles son sus posibles consecuencias.
Cuando los usuarios inician sesión en un sitio, permanecen conectados durante cierto tiempo —desde días hasta meses— antes de tener que volver a autenticarse. Este período durante el cual están autenticados se llama sesión. Durante una sesión activa, el servidor crea un identificador o token único y aleatorio —un ID de sesión— y lo asocia con esa sesión. Luego, el servidor devuelve el ID de sesión al usuario, que se almacena en las cookies del navegador (datos asociados al navegador del usuario durante una sesión).
Cada vez que el usuario realiza una solicitud que modifica el estado del sitio web (por ejemplo, al enviar un formulario), la solicitud incluye el ID de sesión. El servidor compara el ID con el token que tiene almacenado. Si los valores coinciden, autoriza la solicitud y la aplicación ejecuta la acción. De lo contrario, revoca el acceso.
En un ataque CSRF típico, los atacantes aprovechan la confianza en las sesiones de usuarios autenticados y crean solicitudes maliciosas que suplantan una acción en nombre de una víctima que inició sesión. Los actores maliciosos pueden ejecutar ataques CSRF mediante técnicas de ingeniería social, como incluir enlaces dañinos en correos electrónicos o sitios web que visitan los usuarios objetivo. Las aplicaciones web sin protección pueden autorizar inadvertidamente estas solicitudes como acciones legítimas del usuario porque incluyen credenciales válidas.
Lo que está en juego con los ataques CSRF es mucho. Por ejemplo, la brecha de seguridad de Facebook de 2018 afectó a más de 50 millones de cuentas en todo el mundo. ¿La causa? Tokens de acceso con protección insuficiente, vulnerables al uso indebido entre orígenes para autenticar solicitudes del lado del cliente. Esta falta de seguridad adecuada comprometió datos sensibles de los usuarios y provocó pérdidas financieras, daños a la reputación y consecuencias legales. Las brechas de seguridad pueden hacer que se pierda la confianza de los clientes y perjudicar la reputación de una organización y sus servicios.
El impacto de los ataques CSRF exitosos varía según la aplicación objetivo y las funciones que ofrece al usuario. Entre las posibles consecuencias de un ataque CSRF exitoso se encuentran:
Manipulación de datos — Los ataques CSRF pueden permitir que los atacantes manipulen datos sensibles en una aplicación web. Esto podría implicar modificar la configuración del perfil de un usuario, cambiar las preferencias y la configuración de la cuenta, y alterar los datos que puede modificar según sus niveles de acceso.
Acciones no autorizadas — Un atacante puede falsificar solicitudes para ejecutar acciones que el usuario autenticado no autorizó. Algunos ejemplos son enviar formularios, realizar transacciones financieras y eliminar contenido.
Divulgación de información — Los atacantes pueden aprovechar vulnerabilidades para engañar a los usuarios y hacer que revelen datos confidenciales, como mensajes privados y datos financieros. También pueden engañar al usuario para que revele datos propietarios almacenados en la aplicación.
Secuestro de cuentas — Si engañan a los usuarios para que realicen acciones que modifican las credenciales de sus cuentas, como cambiar los datos de inicio de sesión, los atacantes pueden obtener acceso y control no autorizados de las cuentas comprometidas. Esto les permite suplantar al usuario legítimo, acceder a recursos restringidos y, potencialmente, lanzar otros ataques dentro de la aplicación o contra otros usuarios.
Estrategias de protección contra CSRF
Estas son algunas técnicas principales para proteger las aplicaciones de Node.js contra ataques CSRF:
Usa el patrón de token sincronizador (STP)
El patrón de token sincronizador requiere generar un token único para cada sesión de usuario. Se incluye en los envíos de formularios o mediante una solicitud AJAX, como valor de un encabezado personalizado o parte de una carga JSON. El servidor valida este token al recibir las solicitudes.
El STP genera un token aleatorio único para cada sesión de usuario: un token CSRF. Como parte de la carga de respuesta, por ejemplo, una respuesta HTML o JSON, el servidor envía el token CSRF al usuario. La aplicación incluye el token en los encabezados de la solicitud o como parámetro POST personalizado en cada solicitud posterior. Luego, el servidor verifica que el token recibido exista y coincida con el token de la sesión del usuario. Si es así, la solicitud proviene de un usuario legítimo con una sesión válida.
El STP es fácil de implementar y eficaz contra vectores de ataque comunes. Sin embargo, puede requerir administración adicional del estado del lado del servidor. Si usas cookies para almacenar tokens CSRF con el STP, agrega el prefijo __Host- para mejorar la seguridad de las cookies y evitar que sean accesibles en dominios distintos del dominio donde las configuraste.
Implementa cookies SameSite
La estrategia de cookies SameSite consiste en establecer un atributo SameSite en las cookies de sesión para que la aplicación solo las envíe con solicitudes que se originen en el mismo dominio que los sitios web objetivo. Este método evita que las solicitudes incluyan cookies de otros orígenes. El atributo SameSite acepta dos valores posibles: strict y lax.
Cuando se establece en strict, el navegador solo envía cookies de sesión en contextos propios: no las envía cuando el usuario navega a otro sitio web. Este método evita eficazmente los ataques CSRF provenientes de sitios de terceros maliciosos.
Cuando se establece en lax, el navegador envía la cookie con las solicitudes que se originan en el mismo sitio web (dominio) que la configuró y con solicitudes GET de nivel superior.
Aunque los navegadores modernos aplican automáticamente los atributos de cookies SameSite, los navegadores antiguos y los clientes que no son web, como las aplicaciones móviles, ofrecen compatibilidad limitada. Esta limitación afecta considerablemente la eficacia de las cookies SameSite como mecanismo de defensa contra los ataques CSRF. Por eso, los desarrolladores deben considerar otras estrategias de protección contra CSRF y garantizar una protección integral en diversos entornos de cliente.
Usa el patrón Double Submit Cookie
El patrón Double Submit Cookie emite una cookie adicional con un token único, además de los identificadores de sesión estándar. Esta cookie se adjunta a los encabezados de las solicitudes del lado del cliente o a los datos del formulario al enviarlos. El patrón Double Submit Cookie reduce la carga de administración del estado sin afectar significativamente el rendimiento general. Por eso, es ideal para aplicaciones sin estado que usan diversas redes de distribución de contenido o arquitecturas de microservicios.
Sin embargo, este método no protege contra ataques avanzados que apuntan a mecanismos de almacenamiento del navegador donde se guardan tokens secundarios. Un vector de ataque de este tipo es el secuestro de scripts entre sitios (XSS). Las aplicaciones vulnerables a ataques XSS pueden permitir que el atacante obtenga el token único de una cookie y lo use en solicitudes maliciosas posteriores.
Además, el patrón Double Submit Cookie es vulnerable a ataques de intermediario (MITM) cuando los usuarios no configuran las medidas de seguridad adecuadas. El atacante puede interceptar el token CSRF original de la solicitud inicial del cliente y usarlo para crear solicitudes maliciosas.
Puedes usar cookies Double Submit firmadas para hacer más sólido el patrón Double Submit Cookie. Esta estrategia utiliza una clave secreta que solo conoce el servidor, lo que garantiza que un atacante no pueda generar e insertar su propio token CSRF.
Entre las medidas adicionales para reforzar la seguridad se encuentran aplicar el encabezado de respuesta HTTP Strict-Transport-Security (HSTS) y usar prefijos de cookies, como __Host-. Sin embargo, al momento de redactar este artículo, el 25 % de los navegadores no admite prefijos de cookies.
Implementar protección contra CSRF en una aplicación de Node.js
Ahora que revisamos las estrategias para proteger nuestras aplicaciones contra ataques CSRF, veamos cómo implementarlas. Para seguir los pasos, asegúrate de tener:
Node.js instalado en tu computadora.
Un editor de código. En esta guía usaremos Visual Studio (VS) Code
Un navegador web
Una cuenta gratuita de Snyk, la interfaz de línea de comandos (CLI) de Snyk Code y la extensión de Snyk para VS Code
Crearemos una aplicación sencilla de Node.js que ayuda a los usuarios a transferir fondos a otros usuarios. Esta aplicación usará el framework web Express.
Primero, crea una carpeta para el proyecto y llámala nodejs-csrf-strategies. Abre esta carpeta en una terminal y ejecuta el comando npm init -y para inicializar un proyecto de Node.js. A continuación, ejecuta el comando npm i express para instalar el framework web Express.
Crea un archivo llamado index.js y pega el siguiente código.
En esta aplicación de ejemplo, una ruta / muestra el formulario HTML para ingresar la cantidad de fondos que se transferirá. Luego, la ruta /transfer devuelve un mensaje que indica que se transfirió correctamente la cantidad ingresada en el formulario. En una aplicación real, aquí implementaríamos la lógica de transferencia. Ten en cuenta que el código de esta aplicación es vulnerable a ataques CSRF: no lo uses en producción.
Después de instalar la CLI de Snyk en tu computadora, habilita Snyk Code y analiza el proyecto de ejemplo para detectar vulnerabilidades con Snyk Code. La CLI de Snyk te permite integrar las funciones de Snyk Code en tu flujo de desarrollo y ejecutar pruebas de Snyk Code de forma local para revisar si el código de tu aplicación tiene vulnerabilidades de seguridad.
Para hacerlo, abre la carpeta del proyecto en la terminal. Ejecuta el comando snyk code test. Deberías obtener un resultado como el de la siguiente captura de pantalla, con detalles sobre la transmisión de información sensible en texto sin cifrar, el uso de un hash de contraseña con esfuerzo computacional insuficiente, la exposición de información, CSRF, la denegación de servicio por expresiones regulares (ReDOS) y XSS.

Este resultado significa que la aplicación es vulnerable a ataques CSRF y a los demás ataques mencionados.
Pasa el cursor sobre la línea que inicializa la aplicación Express —const app = express()— para consultar información detallada de Snyk sobre los ataques CSRF y las prácticas recomendadas para prevenirlos, como se muestra en la siguiente captura de pantalla. La extensión de Snyk para VS Code hace posible esta detección de vulnerabilidades en tiempo real y te ayuda a descubrirlas mientras escribes código.

Ahora que Snyk Code identificó que nuestra aplicación de Node.js es vulnerable a ataques CSRF, exploremos cómo pueden ayudar las protecciones contra CSRF que mencionamos.
Protege nuestra aplicación con el STP
Implementemos el STP en la aplicación de ejemplo de Node.js. Primero, instala el middleware csurf con el comando `npm install csurf`. Este middleware requiere que inicialices un middleware de sesión o un analizador de cookies. En este ejemplo, usaremos el analizador de cookies.
Instala un analizador de cookies con el comando npm install cookie-parser.
A continuación, importa el middleware y el analizador de cookies al inicio de tu archivo JavaScript.
Habilita el análisis de cookies y configura el middleware de rutas agregando el siguiente código justo antes de la ruta GET.
Debemos analizar las cookies porque la opción de cookies está configurada como true en csrfProtection.
Ahora, incluye el token CSRF generado como campo de entrada oculto al mostrar el formulario HTML. De esta manera, el token CSRF se incluye en el formulario HTML para su envío. Reemplaza el código de la ruta GET por el siguiente.
Modifica la ruta POST con el siguiente código para aplicar el middleware csrfProtection.
Este middleware verifica las solicitudes POST entrantes comparando el valor del campo _csrf que la aplicación envió en el cuerpo de la solicitud con el token CSRF almacenado en la sesión del usuario. Este último está asociado con sus cookies.
Cómo proteger nuestra aplicación con cookies SameSite
Implementemos cookies SameSite en la aplicación de Node.js que creamos antes. Primero, instala el middleware cookie-parser con el comando npm install cookie-parser. Importa el middleware cookie-parser en la aplicación e inicialízalo con una clave secreta mediante el siguiente código.
El valor de <your-secret-key> debe ser una cadena única de caracteres que se use para firmar las cookies: un valor aleatorio, extenso e impredecible, generado mediante un método criptográficamente seguro.
Al firmar una cookie con esta cadena única, se genera un hash de su contenido y se crea una firma única. Cuando el servidor recibe la cookie del navegador más adelante, puede verificar su integridad comprobando la firma con la misma clave secreta única.
Este método ayuda a prevenir el secuestro de sesiones, en el que un atacante intenta robar o suplantar la sesión de un usuario. Si un atacante modifica la cookie, la firma deja de coincidir y el servidor detecta que la cookie fue manipulada. Así, los atacantes no pueden modificar los datos de sesión almacenados en las cookies.
Cómo proteger nuestra aplicación con el patrón Double Submit Cookie
Para implementar el patrón Double Submit Cookie, instala cookie-parser. Luego, agrega el siguiente código a la aplicación para importar los paquetes necesarios y habilitar el análisis de cookies.
Ahora, crea funciones de middleware para generar y validar tokens CSRF con el siguiente código.
Luego, aplica el middleware generateCSRFToken a la ruta GET.
Por último, aplica la función de middleware validateCSRFToken a la ruta POST.
Pruebas de protección contra CSRF
Es fundamental probar la protección contra CSRF para:
Prevenir acciones no autorizadas — Puedes verificar que la aplicación de Node.js y otras estrategias implementadas validen y verifiquen correctamente las solicitudes para prevenir acciones no autorizadas.
Proteger los datos y la privacidad de los usuarios — Puedes asegurarte de que los datos de los usuarios permanezcan seguros y protegidos durante ataques CSRF que buscan exponer o manipular información confidencial.
Cumplir con los estándares de seguridad — Muchos estándares y regulaciones de seguridad, como el Estándar de Seguridad de Datos de la Industria de Tarjetas de Pago (PCI DSS), exigen que las organizaciones implementen protección contra CSRF. Probar esta protección permite verificar el cumplimiento de dichos estándares y ayuda a evitar sanciones o problemas legales.
Identificar vulnerabilidades — Al simular ataques y probar la solidez de las medidas de seguridad contra CSRF, puedes identificar y corregir vulnerabilidades antes de que personas malintencionadas las exploten.
Podemos usar un formulario HTML personalizado para simular un ataque CSRF contra el código original, sin modificar, de index.js que aparece al inicio de este tutorial. Considera el siguiente formulario HTML.
Este formulario HTML personalizado muestra al usuario un mensaje tentador: dice que ganó un premio de $100 y le pide que lo reclame haciendo clic en el botón. Al mismo tiempo, un formulario oculto envía el monto al endpoint /transfer sin que el usuario lo sepa. El código de la etiqueta <script> del formulario HTML envía el formulario automáticamente cuando se carga la página. Con el código original, la transferencia se completaría porque el servidor no podría detectar ataques CSRF.
Para probar una de las estrategias de protección contra CSRF que implementamos, inicia el servidor después de aplicar la estrategia STP. Luego, intenta enviar el formulario HTML personalizado. El servidor mostrará el error ForbiddenError: invalid csrf token y no procesará la transferencia. Esto demuestra que la estrategia de protección contra CSRF funciona según lo previsto.
Para probar cada estrategia implementada:
STP — Crea una solicitud sin el token correcto o con uno vencido. Observa si el servidor la rechaza.
Cookies SameSite — Realiza solicitudes de origen cruzado desde distintos dominios. Comprueba si los servidores deniegan el acceso no autorizado cuando faltan las cookies de sesión.
Double Submit Cookies — Envía una solicitud con tokens que no coincidan en los datos enviados o en los encabezados y las cookies de sesión. Asegúrate de que los servidores los validen correctamente.
Ahora, usa Snyk para probar si el código actualizado tiene vulnerabilidades. Puedes probar el código para otras estrategias, pero en esta demostración nos centraremos en el código que implementa la estrategia STP.
Ejecuta el comando snyk code test para buscar vulnerabilidades. Deberías obtener un resultado como el de la siguiente captura de pantalla.

Los resultados muestran que el código presenta vulnerabilidades de exposición de información y XSS, pero no de CSRF. Esto significa que corregimos la vulnerabilidad CSRF que detectamos antes.
Prácticas recomendadas para proteger aplicaciones de Node.js contra CSRF
Además de implementar las estrategias anteriores, refuerza la protección contra CSRF con estas prácticas recomendadas:
Actualiza periódicamente las dependencias y el middleware para mantener las configuraciones de seguridad al día. Herramientas como Snyk Open Source agilizan este proceso, ya que identifican componentes desactualizados y sugieren parches.
Implementa una política de seguridad del contenido (CSP) que restrinja las solicitudes a fuentes confiables y reduzca los posibles vectores de ataque.
Combina varias técnicas de protección contra CSRF, como STP con cookies SameSite, o usa Double Submit Cookies junto con la aplicación de CSP. Este enfoque por capas minimiza las vulnerabilidades que podrían surgir si dependes de una sola estrategia.
Próximos pasos
Comprender los ataques CSRF y sus implicaciones es fundamental para proteger las aplicaciones de Node.js. Implementar estrategias de protección sólidas, probarlas eficazmente y seguir las prácticas recomendadas refuerza las defensas de la aplicación contra las amenazas.
Probar periódicamente las vulnerabilidades —como CSRF— e implementar mecanismos de seguridad sólidos ayuda a mitigar los riesgos y prevenir acciones no autorizadas. Aplica medidas de seguridad proactivas y técnicas actualizadas para crear aplicaciones de Node.js seguras y corregir las vulnerabilidades antes de que las exploten personas malintencionadas.
Para proteger tus aplicaciones de Node.js, aplica los conceptos y las estrategias de este artículo y prueba Snyk Code.
Empieza con Capture the Flag
Aprende a resolver desafíos de Capture the Flag viendo nuestro taller virtual introductorio a pedido.
