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.
Community Posts
No posts yet. Be the first to write about this video!
Write about this video