7 consejos para evitar ser hackeado (npm, pnpm y bun)

BBetter Stack
Computing/SoftwareInternet Technology

Transcript

00:00:00Si instalas paquetes de NPM, eres un objetivo. Quizás no hoy, quizás no esta semana, pero
00:00:05definitivamente va a pasar. Hemos tenido cientos de paquetes comprometidos solo en los últimos meses,
00:00:09y no está disminuyendo. Así que, en lugar de preocuparme cada vez que surge uno de estos,
00:00:14realmente fui y bloqueé mi propia configuración en NPM, PNPM y BUN, y resulta que la mayoría
00:00:18de las cosas que te habrían salvado toman unos 30 segundos en configurarse. Así que en este video,
00:00:23te mostraré los siete cambios que hice, desde una línea de cambio en la configuración que
00:00:27elimina el ataque más común directamente, hasta herramientas gratuitas que los propios atacantes
00:00:30enviaron y que los detectarían antes de que el paquete llegue a tu máquina. Vamos allá.
00:00:39El primero y más sencillo es simplemente dejar de descargar paquetes nuevos. La mayoría de estos ataques
00:00:44a la cadena de suministro se detectan en cuestión de horas, así que si simplemente no instalas versiones
00:00:48completamente nuevas en cuanto salen, realmente evitas la mayoría de estos ataques a la cadena de suministro.
00:00:52Todos los principales administradores de paquetes de Node.js ofrecen ahora alguna forma de control de edad de lanzamiento.
00:00:57Para NPM, lo configuras en el archivo .npmrc, y se establece en días. Para PNPM, puedes configurarlo globalmente en el archivo pnpm-config.yaml,
00:01:03o puedes establecer esto proyecto por proyecto usando el archivo pnpm-workspace.yaml, y este valor realmente
00:01:08se establece en minutos. Y también vale la pena notar que desde PNPM 11, esto ya tiene un valor predeterminado de un día,
00:01:14así que incluso si no lo configuras, todavía tienes algo de protección. Para BUN, lo configuras en el
00:01:17archivo bunfig.toml, ya sea globalmente o de nuevo por proyecto, y este se establece realmente en segundos.
00:01:23Realmente me sorprende que en tres administradores de paquetes para la misma configuración, hayamos terminado con
00:01:27tres valores diferentes, y resume bastante bien este ecosistema. Una vez que tienes esto configurado,
00:01:32si luego instalas un paquete como react-start de tanstack, puedes ver que no instala la
00:01:36versión, realmente instala la más reciente que cumple con mis criterios de edad de lanzamiento, que para mí
00:01:41fue hace una semana. Ahora, si alguna vez necesitas saltarte esto, quizás hubo un problema de seguridad con el
00:01:45paquete que estás instalando y necesitas instalar la última versión, aún puedes hacerlo
00:01:49desde la línea de comandos, pero ten cuidado con los LLMs aquí también, ya que he visto casos donde los LLMs
00:01:54simplemente usan esto para omitir y de todas formas instalar las versiones más recientes. Otra cosa a tener en cuenta es
00:01:59que NPX y BUNX no respetan esta configuración, de hecho todavía instalan la última versión,
00:02:03y hay una solicitud de extracción (PR) abierta en BUN para arreglar esto. Ahora, mientras estamos en esta configuración, vamos a
00:02:07desactivar también los scripts de instalación para NPM. PNPM y BUN de hecho tienen este comportamiento por defecto,
00:02:12así que no hay nada que configurar para ellos. Si no lo sabías, cuando instalas un paquete, ese paquete tiene
00:02:16permitido ejecutar su propio código justo después de haber sido instalado, y esto se hizo para casos de uso legítimos
00:02:20como compilar código nativo o descargar un binario, pero el problema es que casi todos los ataques
00:02:26a la cadena de suministro han usado este método para ejecutar código malicioso en tu máquina justo después de instalar.
00:02:30Si encuentras un paquete que tiene una necesidad legítima de uno de estos scripts, aún puedes habilitarlo
00:02:34explícitamente. En PNPM, cuando instalas un paquete que tiene scripts de post-instalación, te avisará,
00:02:39como esbuild aquí, y luego puedes ejecutar "pnpm approved-builds" para elegir cuáles permitir,
00:02:44y esto en realidad establece tu configuración de "allowed-builds" en el espacio de trabajo de PNPM, y también puedes simplemente usar la
00:02:48bandera "--allow-build" en el comando de instalación para hacer lo mismo. Para BUN, como dije, detiene estos
00:02:52scripts de instalación por defecto también, pero vale la pena saber que de hecho tiene una lista seleccionada de
00:02:56paquetes que tienen permitido ejecutar estos scripts, y eso incluye los que tengo instalados como
00:03:00esbuild. Puedes optar por no participar añadiendo "trustedDependencies" en tu package.json,
00:03:04de esta manera solo los paquetes que permitas explícitamente podrán ejecutar scripts de post-instalación.
00:03:09También dice que si configuras la matriz como vacía, debería anular esa lista predeterminada
00:03:12también, pero no parece estar funcionando para mí, y parece ser un error que encontré en GitHub
00:03:17también. La solución para esto en este momento es simplemente poner un valor en esa lista, y entonces la lista
00:03:21predeterminada se ignora. Con BUN, también puedes ejecutar "bun pm untrusted" para ver qué paquetes quieren ejecutar
00:03:26scripts pero aún no son de confianza, y luego puedes ejecutar "bun pm trust" para permitir uno, o simplemente añadirlo a esa
00:03:30matriz de dependencias de confianza. También puedes desactivar por completo los scripts en BUN configurando "install-scripts" como
00:03:35false en tu archivo global bunfig. Para NPM, esto es un poco más difícil. Honestamente, simplemente no uses
00:03:40NPM, usa PNPM, pero si realmente tienes que usar NPM por alguna razón, puedes obtener un comportamiento de lista permitida similar
00:03:45usando el paquete "allow-scripts" de Lavanet. De esta manera, es solo una lista permitida en tu
00:03:50package.json también. El tercer consejo es bloquear dependencias basadas en git. Con NPM, una dependencia puede
00:03:55de hecho declararse como una URL de git, lo que evita el registro, y puede incluso enviar su propio .npmrc que
00:04:01reactiva los scripts de ciclo de vida. Este es de hecho uno de los trucos usados en el reciente ataque a la cadena de suministro de NPM
00:04:05que afectó a TanStack. Puedes detener esto configurando "allow-git" como "none" en tu configuración de NPM,
00:04:10lo cual los bloquea por completo, y la otra opción es configurar esto en "root", lo cual sí permite que las
00:04:15dependencias basadas en git se instalen, pero solo si están declaradas en tu package.json raíz, así que es probable que
00:04:19estén configuradas explícitamente por ti. Para PNPM, esta opción es "lockfile-only" para dependencias exóticas. Cuando esto se configura como true,
00:04:25solo las dependencias directas, es decir, las que tienes listadas en tu package.json raíz, pueden usar fuentes exóticas
00:04:29como repositorios git o URLs directas de archivos tar. Esta opción no existe en Bun todavía, pero hay
00:04:35una PR abierta para añadir esto, así que quizás la veamos pronto. Como un bono para terminar los consejos que involucran cambios de
00:04:40configuración, PNPM de hecho tiene una configuración de "trust-policy", que podemos establecer en "no-downgrade", y esto significa
00:04:45que PNPM fallará si el nivel de confianza de un paquete ha disminuido en comparación con su lanzamiento anterior. Así que si un
00:04:50paquete fue publicado previamente por un editor de confianza, pero ahora solo tiene procedencia o
00:04:55ninguna evidencia de confianza, la instalación fallará. Esto debería ayudar a detectar esos ataques que encuentran formas de
00:05:00eludir los procesos habituales de publicación. El consejo número cuatro, sin embargo, es probablemente el más poderoso, que es
00:05:04usar una herramienta que realmente examine los paquetes que estás instalando y pueda auditarlos antes de que
00:05:08toquen tu máquina. Para eso, tenemos dos herramientas poderosas y completamente gratuitas. La primera es
00:05:14NPQ. Puedes configurar esto creando un alias para tus comandos normales de NPM, PNPM o Bun,
00:05:18de modo que cada vez que ejecutes una instalación, realmente verifique algunas cosas. Escaneará en busca de vulnerabilidades conocidas
00:05:23en la base de datos de Snyk, y marcará cualquier paquete que tenga menos de 22 días de antigüedad. Detectará
00:05:28el "typosquatting", que es cuando alguien publica un paquete como "express" con dos "s", esperando
00:05:32que cometas un error tipográfico e instales ese en su lugar. Verificará la firma del registro y
00:05:37la procedencia de la construcción. Te avisará cuando un paquete tenga scripts de pre y post instalación, y además de todo eso,
00:05:41verifica cosas básicas como la cantidad de descargas, si hay un archivo README, una licencia, una URL de repositorio,
00:05:46y cuál es el correo electrónico del mantenedor, y si ese dominio incluso sigue registrado. Hace todo esto
00:05:51y luego te da un informe interactivo sobre tus paquetes, donde todavía puedes decidir si
00:05:55quieres instalarlo. La segunda es Socket Firewall. Esta es de hecho la que uso,
00:05:59y de nuevo, creas un alias para todos tus gestores de paquetes habituales, y esta de hecho admite
00:06:03otros lenguajes además de JavaScript, como Python y Rust. Similar a NPQ, cuando ejecutas una instalación con
00:06:08esto, verificará Socket y bloqueará cualquier paquete malicioso confirmado por humanos, y también te avisará
00:06:12sobre cualquier amenaza detectada por IA, que son las que aún no han sido revisadas por humanos. Para ser honesto,
00:06:16elegí principalmente Socket Firewall porque fue la que escuché primero, pero también confío en Socket ya que han
00:06:21atrapado muchos de los paquetes maliciosos recientes, y los atacantes incluso hicieron una entrevista donde dijeron
00:06:25que Socket detectará el malware antes de que el paquete llegue a tu máquina, lo cual es un anuncio bastante bueno
00:06:30para ellos, y también me gusta que admita más que solo JavaScript con "uv", "pip" y "cargo".
00:06:35Si instalas cualquiera de estas, querrás asegurarte de limpiar la memoria caché de tu administrador de paquetes
00:06:38solo para asegurarte de que cada paquete instalado sea verificado por el firewall. El quinto consejo es sobre tus
00:06:42archivos de bloqueo ("lock files"). Tus archivos de bloqueo son donde vive la URL de descarga real de cada paquete, y el
00:06:47problema es que prácticamente nadie revisa sus archivos de bloqueo en una PR. Así que si alguien abre una PR contra tu
00:06:51repositorio, puede editar silenciosamente una URL resuelta para apuntar a un paquete que ellos controlan, y también establecer el
00:06:56hash de integridad correspondiente para que nada parezca extraño. Ahora, la próxima vez que ejecutes una instalación, estás extrayendo
00:07:01el código desde el servidor del atacante. Pero la buena noticia es que si usas PNPM, no eres vulnerable
00:07:05a esto. No mantiene esas fuentes de tablas que pueden ser intercambiadas, y tampoco instalará
00:07:09nada que esté en el archivo de bloqueo, pero que no esté realmente declarado en tu package.json. No pude encontrar
00:07:14información concreta sobre Bun, así que eso podría seguir siendo vulnerable a esto. La solución, si no
00:07:18estás usando PNPM, es usar una herramienta llamada "lockfile-lint". Lo instalas como una dependencia de desarrollo, y valida
00:07:23tu archivo de bloqueo, verificando que cada paquete se resuelva desde un host confiable, como el registro de NPM. Verifica
00:07:28que las URLs resueltas realmente coincidan con el nombre del paquete, y también verifica que los hashes de integridad sean reales
00:07:32también. Si sospecha que algo ha sido manipulado, fallará en la instalación. El sexto consejo es dejar
00:07:37de usar "npm install" en CI y producción, y en su lugar usar la instalación limpia. El comando para esto en NPM es
00:07:42simplemente "npm ci", y para Bun y PNPM, de hecho añades la bandera "--frozen-lockfile", pero también tienen comandos
00:07:47CI como alias que hacen lo mismo. PNPM de hecho usa esto por defecto si detecta que está
00:07:52ejecutándose en un entorno CI. El comando de instalación limpia instala exactamente lo que está en el archivo de bloqueo,
00:07:57nada más, y si el archivo de bloqueo y el package.json no están de acuerdo, simplemente se detiene y lanza un error,
00:08:01en lugar de adivinar e instalar de todas formas. Así que esto debería evitar que un atacante logre meter
00:08:05una versión intercambiada. Nada de esto funciona, sin embargo, si no estás confirmando ("committing") tu archivo de bloqueo en primer
00:08:09lugar, así que asegúrate de que esté en el control de versiones y no en tu .gitignore, y admitiré que cuando
00:08:13empecé a aprender a programar de niño, realmente pensé que debías ignorarlos, así que me alegra
00:08:17haber aprendido a confirmarlos. Entonces, esos seis consejos fueron mayormente configuración y herramientas, pero también hay algunos
00:08:21hábitos que puedes adoptar para ayudarte a evitar ataques. El primero es dejar de actualizar ciegamente
00:08:25todo. Es posible que hayas ejecutado "npm update" o las otras versiones de este comando antes, y simplemente
00:08:30actualizado cada dependencia a su última versión de una vez, pero ese es el tipo de comportamiento exacto que estos
00:08:35atacantes esperan, así que revisa realmente estas actualizaciones y pregúntate por qué necesitas
00:08:39actualizarla. El segundo hábito es cada vez más relevante: simplemente usa menos paquetes. Cada
00:08:43dependencia que añades es otra superficie de ataque, y la mayoría de estos ataques se propagan a través de dependencias
00:08:48de una dependencia, por lo que vale genuinamente la pena preguntar por qué necesitas esa biblioteca. Algunos ejemplos comunes que veo de
00:08:53esto son cosas como Lodash para funciones que pueden hacerse con un pequeño fragmento de código, o Axios cuando
00:08:58fetch puede hacer lo mismo. La razón por la que digo que esto se vuelve más relevante es que en la era de la
00:09:03codificación con agentes, es bastante fácil lograr que la IA escriba unas pocas funciones para ti en lugar de usar una dependencia.
00:09:08El tercer hábito es fijar las dependencias a una versión exacta, para que una actualización siempre sea una elección
00:09:12deliberada, pero solo sé que esto solo bloquea los paquetes que eliges en tu package.json,
00:09:17y las dependencias de tus dependencias todavía pueden usar sus propios rangos, que es exactamente por lo que ese
00:09:21periodo de enfriamiento del consejo 1 importa. Todos estos combinados deberían darte algo de tranquilidad de que no
00:09:25instalarás accidentalmente un paquete comprometido. No son invencibles, pero son mucho mejores que
00:09:29nada. El consejo definitivo es simplemente ejecutar todo en un contenedor de desarrollo reforzado, pero siempre he encontrado
00:09:34que eso es un poco molesto, así que termino volviendo al desarrollo local. Si conoces alguna otra forma
00:09:38de protegerte de este tipo de ataque, házmelo saber en los comentarios de abajo, y mientras estás ahí,
00:09:42suscríbete, y como siempre, nos vemos en la próxima.

Key Takeaway

Implementar un periodo de espera para paquetes nuevos, desactivar scripts de post-instalación y utilizar firewalls de paquetes como Socket Firewall reduce drásticamente el riesgo de comprometer entornos de desarrollo mediante dependencias maliciosas.

Highlights

  • Limitar la instalación de paquetes a versiones con al menos un día de antigüedad mitiga gran parte de los ataques a la cadena de suministro.

  • Desactivar los scripts de instalación post-instalación en NPM previene la ejecución de código malicioso inmediato en la máquina local.

  • Configurar 'allow-git' como 'none' en NPM o utilizar 'lockfile-only' en PNPM bloquea dependencias basadas en URLs de git riesgosas.

  • Herramientas gratuitas como NPQ y Socket Firewall analizan automáticamente los paquetes antes de la instalación para detectar malware y typosquatting.

  • El uso de comandos 'npm ci' o '--frozen-lockfile' en entornos de producción e integración continua garantiza que solo se instale el código verificado en el archivo de bloqueo.

Timeline

Control de edad y configuración de scripts

  • Establecer un periodo de retención para nuevas versiones evita instalar paquetes recién publicados y potencialmente comprometidos.
  • NPM, PNPM y BUN permiten configurar este periodo de edad mediante archivos como .npmrc, pnpm-config.yaml y bunfig.toml.
  • Desactivar la ejecución automática de scripts de post-instalación elimina el vector de ataque más común tras añadir una dependencia.

Los administradores de paquetes ofrecen controles de edad de lanzamiento configurables para evitar la adopción inmediata de software no verificado. PNPM 11 incluye esto por defecto con un periodo de un día. La desactivación de scripts de post-instalación impide que los paquetes ejecuten código arbitrario al instalarse, aunque permite habilitar dependencias de confianza específicamente.

Seguridad en fuentes y auditorías

  • Bloquear dependencias basadas en git evita ataques que eluden el registro oficial de paquetes.
  • La herramienta NPQ escanea vulnerabilidades y metadatos de mantenedores antes de permitir la instalación.
  • Socket Firewall bloquea paquetes confirmados como maliciosos y advierte sobre amenazas detectadas por IA antes de que lleguen a la máquina.

Las dependencias de tipo git pueden ocultar archivos de configuración que reactivan scripts de ciclo de vida, lo cual se mitiga restringiendo fuentes exóticas. El uso de firewalls de paquetes mediante alias de comandos permite un análisis interactivo que verifica procedencia, licencias y actividad del mantenedor antes de completar la descarga.

Gestión de archivos de bloqueo y buenas prácticas

  • El uso de archivos de bloqueo (lock files) es obligatorio para asegurar versiones exactas y evitar manipulaciones en las URLs de descarga.
  • Los comandos de instalación limpia como 'npm ci' o '--frozen-lockfile' detienen el proceso si el archivo de bloqueo no coincide con el archivo de configuración.
  • Reducir el número total de dependencias disminuye la superficie de ataque disponible para posibles intrusiones.

Revisar y confirmar los archivos de bloqueo en el control de versiones impide modificaciones silenciosas de fuentes de paquetes. Los comandos de instalación estricta aseguran que solo se despliegue código validado. La adopción de hábitos como evitar actualizaciones masivas ciegas y minimizar el uso de bibliotecas externas reduce aún más la exposición a riesgos en la cadena de suministro.

Community Posts

No posts yet. Be the first to write about this video!

Write about this video