Isaac Kuri

Reseñas, guias y articulos

La importancia de mitigar vulnerabilidades en NodeJS

Al momento de mantener proyectos con npm, yarn o pnpm, las vulnerabilidades suelen ser un aspecto ignorado en el ciclo de mantenimiento de software. Debido a esto, al momento de mitigar vulnerabilidades, acabamos en situaciones donde el software está plagado de vulnerabilidades y, en casos muy drásticos, puede volverse un…

Al momento de mantener proyectos con npm, yarn o pnpm, las vulnerabilidades suelen ser un aspecto ignorado en el ciclo de mantenimiento de software. Debido a esto, al momento de mitigar vulnerabilidades, acabamos en situaciones donde el software está plagado de vulnerabilidades y, en casos muy drásticos, puede volverse un refactor-hell debido al code-debt que esto causa.

Las impliaciones de tener vulnerabilidades son varias, entre ellas:

  • Vulnerar usuarios de tu software, por medio de malware, troyanos o remote-code-execution.
  • Filtraciones de datos.
  • Pérdida de confianza de parte de usuarios e inversionistas.
  • Compromiso de tu infraestructura, por ejemplo, backdoors, DNS hijacks, filtración de tokens, etc.

Todo esto puede ser evitado con buenas practicas de programacion y conocimiento de herramientas que nos incluye nuestros package-manager.

Dando un ejemplo práctico con UELI: https://github.com/oliverschwendener/ueli, que es un lanzador de teclas. Estos son los comandos que utilizaremos y están disponibles en todos los package managers.

  • npm list: Provee una lista de los paquetes instalados en nuestro proyecto.
  • npm audit: Provee una explicación detallada de las vulnerabilidades presentes en el proyecto.
  • npm why <package>: Provee una visualización de qué está requiriendo este paquete.
  • npm audit fix: Realiza las actualizaciones de seguridad que no contengan breaking-changes.
  • npm audit fix –force: Realiza breaking-changes, asumiendo que tú, como desarrollador, implementarás los cambios necesarios para que el programa funcione.

Ejemplo práctico

Empezamos utilizando npm install para instalar las dependencias de UELI.

 >  npm install
added 597 packages, and audited 598 packages in 28s

109 packages are looking for funding
  run `npm fund` for details

2 high severity vulnerabilities

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

Inmediatamente observamos que se nos reportan 2 vulnerabilidades de serveridad high.

Las vulnerabilidades se clasifican en Critical > High > Medium > Low. Una vulnerabilidad crítica usualmente implica remote-code-execution, CISA KEV, infostealers, etc., y debe ser mitigada y resuelta en menos de 48 horas. Severidad high, suelen tener una índole similar, pero por lo general comprometen al servicio, como permitir DDoS. Medium y Low suelen darse plazos de 1-2 meses para solucionarlos, ya que son más difíciles de explotar o bajo condiciones muy específicas.

Ahora utilizaremos npm audit para ver de qué forma nos están vulnerando.

 >  npm audit
# npm audit report

react-router  7.0.0 - 7.14.2
Severity: high
React Router vulnerable to DoS via unbounded path expansion in __manifest endpoint - https://github.com/advisories/GHSA-8x6r-g9mw-2r78
fix available via `npm audit fix`

Vemos que tenemos un caso de Denial of Service (DoS) que es típico de una vulnerabilidad de severidad alta. Y se nos indica que puede ser resuelta de forma automática utilizando npm audit fix.

Antes de eso, utilicemos npm why react-router-dom, para ver el origen de este paquete. Recomiendo hacer esto, ya que en proyectos de muchos años es posible que estemos acarreando paquetes que no utilizamos ya.

 >  npm why react-router-dom
[email protected]
node_modules/react-router-dom
  react-router-dom@"^7.12.0" from the root project

Obviamente, esto es parte del core de React y tenemos que conservarlo. Entonces vamos a resolver la vulnerabilidad utilizando npm audit fix.

 >  npm audit fix

changed 2 packages, and audited 598 packages in 3s

109 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Con esto hemos resuelto las vulnerabilidades en UELI. 🥳

Después de este proceso, recuerda revisar tu build y correr tus tests para verificar que todo esté en orden.

Build:

 >  npm run build

> [email protected] build
> vite build

vite v8.0.10 building client environment for production...
✓ 2340 modules transformed.
computing gzip size...
dist-renderer/settings.html                    1.17 kB │ gzip:   0.49 kB
dist-renderer/search.html                      1.19 kB │ gzip:   0.50 kB
dist-renderer/assets/search-9LK6AzB7.js       53.03 kB │ gzip:  18.81 kB
dist-renderer/assets/settings-Qma3fLX6.js    119.58 kB │ gzip:  30.70 kB
dist-renderer/assets/client-Fp6Dr0P0.js    1,006.29 kB │ gzip: 279.51 kB

✓ built in 441ms
vite v8.0.10 building client environment for production...
✓ 515 modules transformed.
computing gzip size...
dist-main/createEmptyInstantSearchResult-BXd1XI1b.js    0.65 kB │ gzip:  0.37 kB
dist-main/index.js                                      2.92 kB │ gzip:  0.94 kB
dist-main/Core-DQyQ8j0k.js                             76.06 kB │ gzip: 18.80 kB
dist-main/Extensions-BbrEHj29.js                      157.96 kB │ gzip: 38.01 kB

✓ built in 68ms
vite v8.0.10 building client environment for production...
✓ 2 modules transformed.
computing gzip size...
dist-preload/index.js  3.20 kB │ gzip: 0.77 kB

✓ built in 12ms

Tests:


  >  npm run test

> [email protected] test
> vitest run

 RUN  v4.1.5 /home/isaac/repositories/ueli/srcTest Files  149 passed (149)
      Tests  697 passed (697)
   Start at  20:26:11
   Duration  2.37s (transform 19.98s, setup 0ms, import 27.96s, tests 1.23s, environment 11ms)

Dependabot

Cabe mencionar que una herramienta para estar al día es Dependabot, que automáticamente provee de PRs en tus repositorios que mitigan vulnerabilidades que pueden ser resueltas sin cambios al código. El repositorio de UELI tiene Dependabot implementado y se refleja en el bajo número de vulnerabilidades que encontramos; ¡por lo general, los proyectos pueden llegar a tener cientos de vulnerabilidades!

Revisa los PRs para verlo en acción: https://github.com/oliverschwendener/ueli/pull/1523 (Aquí se está solucionando la vulnerabilidad del artículo).

Aprende más sobre Dependabot aquí: https://docs.github.com/en/code-security/tutorials/secure-your-dependencies/dependabot-quickstart

Glosario

  • code-debt: Es el costo futuro oculto de rehacer el trabajo debido a la elección de soluciones de software rápidas a corto plazo en lugar de las óptimas a largo plazo. Al igual que la deuda financiera, acumula “intereses”, haciendo que el desarrollo futuro sea más lento y costoso si los atajos no se corrigen con el tiempo.
  • refactor: Es el proceso de reestructurar el código existente para mejorar su diseño interno y legibilidad sin alterar su comportamiento externo. Es la herramienta clave para pagar los “intereses” de la deuda técnica, transformando soluciones improvisadas en código limpio, mantenible y preparado para el futuro.
  • breaking-changes: Cambios en dependencias que requieren intervencion del desarollador. Por ejemplo cambio en interfaces y parametros de funciones que son parte del paquete.

+ ,

Dejar un comentario