Video Summary and Transcription
La charla de hoy se centra en asegurar la cadena de suministro de software, especialmente en el ecosistema de JavaScript. El número de dependencias transitivas en proyectos de JavaScript puede contribuir a vulnerabilidades. Los ataques a la cadena de suministro de código abierto han aumentado significativamente, lo que ha llevado a iniciativas para mejorar la seguridad de la cadena de suministro. La precisión en las dependencias del gestor de paquetes es crucial, y el almacenamiento en caché y la agrupación de dependencias pueden ayudar a lograr instalaciones reproducibles. Mitigar las amenazas implica escaneo activo, creación de perfiles y compartir información. Herramientas como NPM Audit Signatures pueden verificar la integridad de los paquetes. Los desarrollos futuros incluyen instalaciones reproducibles y consultas de dependencias poderosas.
1. Introducción a la seguridad de la cadena de suministro de software
Hoy hablaré sobre cómo asegurar tu cadena de suministro de software, centrándome específicamente en la cadena de suministro de JavaScript o Node. Tengo más de 20 años de experiencia en desarrollo de ingeniería, incluyendo consultoría y contribuciones de código abierto. Soy cofundador de Themify y fui el director de ingeniería de los equipos de NPM CLI y GitHub CLI. Echemos un vistazo rápido al estado del ecosistema, centrándonos en los gestores de paquetes y su interacción con las dependencias. El ecosistema de NPM tiene más de 2.3 millones de paquetes y miles de millones de descargas al mes, siendo las dependencias transitivas un factor importante.
tu cadena de suministro de software. Específicamente, hablaré sobre cómo puedes asegurar tu cadena de suministro de JavaScript o Node. Si quieres seguir la presentación, el enlace a las diapositivas es bit.ly. O puedes escanear el código QR que verás aquí junto a la charla y espero que los enlaces y toda la información que encuentres te sea útil, siéntete libre de compartirla con amigos. Y vamos a sumergirnos. Un poco sobre mí. Mi nombre es Darcy Clark nuevamente. He estado trabajando en desarrollo de ingeniería y diseño durante más de 20 años. He trabajado como consultor para varias marcas, agencias, startups y organizaciones grandes y pequeñas. También he estado activo en la comunidad de código abierto durante más de 15 años. Es posible que conozcas algunos de mis trabajos. Cofundé una empresa llamada Themify en 2011, 10 u 11. También fui el director de ingeniería de los equipos de NPM CLI y GitHub CLI, y formé parte de la adquisición de NPM por parte de GitHub en 20. Vivo aquí en Toronto, Canadá, como podrás ver en mi sombrero. Y si quieres seguirme, puedes hacerlo. Estoy en Twitter, soy D'Arcy, ese es mi nombre de usuario, o puedes obtener más información sobre mí en mi sitio web.
Un poco sobre lo que he estado haciendo en los últimos tres o cuatro años. Estuve a cargo del equipo de NPM CLI, como dije, y ese equipo en realidad respaldaba aproximadamente 100 proyectos o paquetes de NPM, lo que representaba aproximadamente el 2% de todo el tráfico del registro que vimos o dicho de otra manera, había alrededor de 3 mil millones de descargas al mes para los proyectos y los proyectos del portafolio que mi equipo respaldaba. Así que echemos un vistazo rápido al estado del ecosistema tal como está hoy. En el ecosistema tenemos entornos de ejecución, gestores de paquetes, lenguajes y transpiladores, y prácticamente todo lo demás cae en la última categoría de herramientas de construcción, empaquetadores, frameworks y más. Y cuando hablamos de la cadena de suministro dentro de la gestión de paquetes específicamente, hablamos de los paquetes disponibles en NPM. Y eso se reduce a estas tres áreas principales, gestores de paquetes, transpiladores y todo lo demás. El área en la que nos vamos a centrar hoy son los propios gestores de paquetes. Cómo interactúan con esas otras dependencias, las sutilezas que puedes encontrar con ellos y, en esencia, algunas de las nuevas herramientas y características interesantes que están llegando a los gestores de paquetes para ayudar a asegurar tus dependencias. Y, por supuesto, JavaScript es conocido por tener una gran cantidad de dependencias. El ecosistema de NPM tal como está hoy en día tiene más de 2.3 millones de paquetes y ve aproximadamente 200 y casi 220 mil millones de descargas al mes. ¿Y por qué es eso? Bueno, no son las dependencias directas. En promedio, la estadística del estado del universo de GAP en 2020 y 2021 indica que los proyectos de JavaScript no tienen tantas dependencias directas, aproximadamente 10 en promedio. Pero en realidad son las dependencias transitivas las que representan la mayoría de la carga innecesaria que se encuentra en el ecosistema de NPM.
2. Dependencias transitivas en el ecosistema de JavaScript
En el ecosistema de JavaScript, los proyectos tienen un promedio de 683 dependencias transitivas. Las dependencias transitivas son aquellas que se incluyen debido a las dependencias directas. Estas dependencias pueden representar el 5% de las vulnerabilidades. (Fuente: Informe de Snigg sobre el ecosistema de seguridad de código abierto de 2020).
En el ecosistema de JavaScript. En promedio, se pueden encontrar aproximadamente 683 dependencias transitivas en esos proyectos. ¿De qué estamos hablando cuando mencionamos las dependencias transitivas? Este gráfico debería darte una idea de lo que queremos decir con transitivas. El paquete A depende de los paquetes B y D, y el paquete B también depende del paquete C. El paquete C es lo que llamamos una dependencia transitoria, es decir, una dependencia que no ha sido definida por el nodo raíz o el proyecto raíz y se ha incluido debido a una de tus dependencias directas. Se estima que el mismo 5% de las vulnerabilidades se encuentran en esas dependencias transitivas que estamos incluyendo, lo cual es bastante sorprendente. Esta estadística proviene del informe de Snigg sobre el ecosistema de seguridad de código abierto de 2020.
3. Aumento de los ataques a la cadena de suministro de código abierto
Ha habido un aumento significativo en los ataques dirigidos a la cadena de suministro de código abierto, con un aumento interanual del 742%. Según GitHub, hay un 59% de probabilidad de recibir una alerta de seguridad en el próximo año. Muchas empresas están trabajando en iniciativas y productos para abordar la seguridad de la cadena de suministro y aumentar la confianza en el ecosistema de MPM.
Por supuesto, vemos más bromas sobre este problema aquí. El desarrollador promedio parece que no puede escapar de las vulnerabilidades y de informarlas cada vez que ejecuta la auditoría de MPM. Por supuesto, este es un sentimiento válido. Ha habido un aumento de casi el 742% interanual en los ataques dirigidos a la cadena de suministro de código abierto. Y esto es lo que parece cuando se representa gráficamente. Un aumento increíble, que parece que nunca va a detenerse. Según las estadísticas que tenemos de GitHub mismo, el estado del octoverso nuevamente en 2020 y en realidad hay un 59% de probabilidad de que recibas una alerta de seguridad en el próximo año, lo cual es bastante grande. Hay muchas empresas que están tratando de liderar iniciativas e introducir nuevos productos para abordar esto, para abordar la seguridad de la cadena de suministro, para examinar los avisos y aumentar nuestra confianza en el ecosistema de MPM.
4. Dependencias del gestor de paquetes y precisión
Veamos un ejemplo de cómo comenzar un nuevo proyecto y utilizar un gestor de paquetes para instalar dependencias. Los diferentes gestores de paquetes interpretan las dependencias de manera diferente, lo que lleva a variaciones en el número de dependencias instaladas. La precisión es crucial, ya que los gestores de paquetes tienen diferentes interpretaciones de las dependencias y pueden aplicar diferentes reglas. Los falsos positivos son aceptables, pero los falsos negativos son peligrosos. Cachear y agrupar las dependencias con frecuencia puede ayudar a lograr instalaciones precisas y reproducibles.
Veamos un ejemplo de cómo comienzo un nuevo proyecto y qué sucede una vez que comienzo a utilizar un gestor de paquetes para dar forma e instalar dependencias. Aquí he creado un proyecto de Create React App, simplemente ejecutando el instalador normal, y ha creado un archivo package.json con un manifiesto que se ve así. Tiene siete dependencias directas en Jeston, React, UserEvent, Web Vitals, etc.
Si saltamos y vemos qué instalará cada gestor de paquetes con este manifiesto, vemos una amplia variedad en cuanto al número de dependencias instaladas. Hay una diferencia de aproximadamente 850 dependencias entre el número más pequeño y el más grande de dependencias que vemos instaladas. Nuevamente, esto es sin ninguna configuración específica ni configuración adicional para el proyecto de Create React App. Esto es puramente lo que los gestores de paquetes deciden instalar y cómo interpretan el manifiesto de paquetes para ese proyecto.
Tal vez te estés preguntando, espera un segundo. ¿Qué está sucediendo aquí? La precisión es muy importante. En cuanto a los gestores de paquetes, todos tienen diferentes interpretaciones de las dependencias y el archivo de manifiesto. Algunos pueden o no instalar dependencias de desarrollo, dependencias opcionales. Pueden o no interpretar las dependencias agrupadas o dependencias pares, y pueden aplicar anulaciones especiales o algoritmos de resolución que difieren entre sí, lo que significa que la precisión del gráfico depende completamente del gestor de paquetes. Hay una famosa cita de Hércules de Éufrates, un filósofo griego. Dijo: ningún hombre se baña dos veces en el mismo río. El equivalente moderno sería decir que ningún archivo package.json se instala de la misma manera dos veces. Por supuesto, podemos bromear al respecto y decir que prácticamente ninguna instalación de npm será igual. Y esto tiene que ver, en algunos casos, con un problema de mutabilidad. Si te llevas algo de la charla de hoy, ten cuidado con la precisión de las herramientas de auditoría y las herramientas del gestor de paquetes que estás utilizando hoy. De hecho, los falsos positivos están bien. Pueden causar confusión y pueden desperdiciar algo de tiempo adicional, pero los falsos negativos son realmente muy peligrosos. Entonces, ¿qué puedes hacer? Bueno, la mejor manera de manejar esto es cachear y agrupar todas tus dependencias con la mayor frecuencia posible para obtener la instalación más precisa y reproducible.
5. Amenazas y mitigación en la cadena de suministro
Algunas de las mayores amenazas para la cadena de suministro de software son el malware, el typosquatting, la confusión de dependencias, la compromisión del registro y la toma de cuentas. Mitigar estas amenazas implica escaneo activo, creación de perfiles, automatización y compartir información. Heurísticas clave como nombres, recuentos de descargas, versiones y fechas de publicación ayudan a mitigar el typosquatting. También se pueden utilizar políticas y cumplimiento para protegerse contra estas amenazas.
Entonces, ¿cuáles son algunas de las amenazas a la cadena de suministro que vemos más allá de la precisión y la mutabilidad? Algunas de las mayores amenazas para la cadena de suministro de software son el malware, el typosquatting, la confusión de dependencias, la compromisión del registro y la toma de cuentas. Entonces, ¿cómo podemos mitigar el malware? Bueno, tomar un enfoque activo de escaneo de manera regular y crear perfiles sobre cómo se ve y cómo no se ve el malware es importante. Y, por supuesto, la automatización de esas herramientas en el lado del registro, así como en tus instancias privadas, es importante. Y dejar que otros sepan lo que has encontrado es clave para mantenernos seguros.
¿Cómo se puede mitigar el typosquatting? Bueno, hay algunas heurísticas clave que podemos usar. Cosas como nombres, recuentos de descargas, versiones y la fecha de publicación son indicadores de si algo está tratando de ocultarse y pretender ser un paquete popular o seguro dentro del ecosistema. Por supuesto, podemos utilizar políticas y hacer cumplir esas políticas a través de herramientas sobre las personas o heurísticas que hemos creado.
6. Mitigando la Confusión de Dependencias y la Mutabilidad
Para mitigar la confusión de dependencias, utiliza scopes para paquetes internos y asegúrate de configurar el registro en los archivos npm rc. Responde rápidamente a los fallos de construcción. Mitiga la compromisión del registro con el soporte de archivos de bloqueo y verificaciones de integridad. Mitiga la toma de cuentas con la verificación de inicio de sesión y la aplicación de la autenticación de dos factores (2FA). Elimina la mutabilidad eliminando o evitando referencias a paquetes mutables. Utiliza archivos de bloqueo y la bandera 'before' para garantizar instalaciones reproducibles. Considera la precisión de las herramientas de asesoramiento y la herramienta NPM Audit Signatures del CLI de NPM.
Entonces, ¿cómo podemos mitigar la confusión de dependencias? Bueno, el uso de scopes para paquetes internos es una gran herramienta cuando estás alojando un registro de terceros o, en general, tratando de mantener el código privado disponible para los equipos. Asegurarse de que la configuración del registro esté establecida dentro de los archivos npm rc de todos tus proyectos también es clave para garantizar que no intentes acceder a un registro público y descargar software que no pretendes. Por supuesto, responde rápidamente a los fallos de construcción, ya que pueden indicar una mala configuración dentro de tus proyectos.
¿Cómo podemos mitigar la compromisión del registro? Bueno, el gestor de paquetes npm y la mayoría de los gestores de paquetes ya tienen soporte de archivos de bloqueo, que es una de las claves para garantizar que verifiques la integridad de los paquetes que has instalado previamente y has visto antes, y asegurarte de que has almacenado en caché cosas como las verificaciones de integridad y la información SSRI.
¿Cómo podemos mitigar la toma de cuentas? Bueno, el registro de npm y las experiencias en github.com han estado implementando lentamente la verificación de inicio de sesión y la aplicación de la autenticación de dos factores (2FA). Esto incluye mejorar la experiencia de inicio de sesión de 2FA a través de la autenticación web, y también han realizado grandes inversiones en el equipo de soporte y los flujos de autenticación.
Entonces, pasemos a la mutabilidad. Hemos hablado un poco de esto antes, pero esta es una de las áreas de mayor preocupación cuando hablamos de seguridad de la cadena de suministro. Cosas como paquetes remotos de terceros, scripts de instalación y más, todos son la causa de instalaciones mutables.
Entonces, ¿cómo podemos eliminar la mutabilidad en nuestros proyectos? Bueno, comienza eliminando o evitando referencias a paquetes mutables. Dentro del Manifiesto de Paquetes, puedes encontrar referencias a etiquetas de distribución, archivos tar remotos y repositorios git remotos. En todos estos casos, estas son referencias mutables a paquetes, lo cual creará problemas si intentas tener instalaciones reproducibles.
Una gran preocupación aquí es que el registro de npm realmente almacena metadatos de paquetes mutables e inmutables, que no se validan con respecto al archivo tar. Esto es un gran problema y algo que se debe tener en cuenta. Como se mencionó antes, el uso de archivos de bloqueo ayuda a bloquear el valor de integridad de las firmas y, en realidad, la estructura del árbol de tus proyectos. Utilizarlos junto con comandos como 'npm ci' obligará a la reificación del mismo árbol instalado una y otra vez. Es importante comprender qué validación se está realizando y qué no se está realizando. Bueno, hoy en día, la validación de firmas y valores de integridad se realiza en el CLI de npm. Y hay herramientas mejoradas que están por venir.
Otra herramienta que a menudo se pasa por alto, pero que es muy útil cuando hablamos de estados mutables e inmutables de proyectos, es la bandera 'before'. Proporcionar una fecha a 'npm install' en la bandera 'before' te ayudará a fijar las dependencias del registro en un período de tiempo específico. Esto solo funcionará para dependencias o paquetes del registro. No puedes trabajar con dependencias git de terceros o referencias a archivos tar remotos, ya que son mutables.
Echemos un vistazo al estado actual de las soluciones y herramientas que tenemos en el ecosistema. Muchas herramientas de asesoramiento, como Dependent Bot, Renovate y varias otras integraciones de CI, te proporcionan auditorías o información sobre tus proyectos y paquetes. Ten en cuenta que esta información es tan precisa como el gestor de paquetes o el cerebro en el que se realiza el análisis y las ideas. Y como te mostré antes, esto puede variar mucho según las herramientas que utilices.
7. NPM Audit Signatures y la Integridad de los Paquetes
La CLI de NPM tiene una herramienta llamada NPM Audit Signatures que te permite verificar la integridad de los paquetes instalados. Las firmas de los artefactos pueden ser engañosas, por lo que es importante centrarse en el contenido del paquete. No confíes únicamente en estándares, cumplimiento o certificaciones, ya que pueden no reflejar el uso en el mundo real. Ten cuidado con las soluciones milagrosas que afirman resolver todos los problemas.
La CLI de NPM tiene una herramienta llamada NPM Audit Signatures. Hoy en día, puedes utilizar esto para verificar y comprobar que las firmas definidas para los paquetes que has instalado son válidas y que la integridad no se ha corrompido de alguna manera. Las firmas de los artefactos también son un poco engañosas. Puedes firmar cualquier cosa que desees, pero en última instancia, el contenido del paquete es lo más importante. Por supuesto, ten en cuenta los estándares y el cumplimiento. Es importante observar lo que la industria considera como una mejor práctica, pero no siempre lo tomes al pie de la letra. Los estándares y las certificaciones también pueden ser algo engañosos. No tomes ningún certificado o distintivo como algo seguro. A menudo, los estándares y las tareas que se utilizan están desconectados del uso real de las dependencias y pueden dar una falsa sensación de seguridad. Siempre ten cuidado con las soluciones milagrosas. Evita, si puedes, cualquier cosa que diga ser una solución para solucionar todos los problemas.
8. Futuro Estado y Consultas de Dependencias
En el futuro, se están desarrollando instalaciones reproducibles dentro de los ecosistemas de paquetes. Las distribuciones de paquetes permiten definir múltiples variantes del mismo paquete para diferentes plataformas, eliminando la necesidad de scripts posteriores a la instalación. Dota introduce nuevas políticas y permisos, mientras que NPM ha realizado mejoras en la auditoría y ha lanzado el Dependency Selector Synthesis. Este lenguaje permite consultas potentes y expresivas para las dependencias, proporcionando metadatos y filtrado de atributos. El método QuerySelectorAll de la CLI de NPM permite a los desarrolladores front-end utilizar esta sintaxis. Existen selectores como samber y outdated, y hay RFC abiertos para consultas y políticas de auditoría. Puntos clave: la seguridad es un trabajo en equipo, se recomienda NPM para la gestión de paquetes, la curiosidad mejora la seguridad y compartir descubrimientos beneficia a todos.
Echemos un vistazo a lo que depara el futuro estado. Hay esperanza. Se está trabajando en desarrollar instalaciones reproducibles dentro de los ecosistemas de paquetes. Una solución en la que he estado trabajando se llama distribuciones de paquetes. Escribí la especificación en NPM y es la idea de que puedes definir múltiples variantes del mismo paquete, específicas para diferentes plataformas, y básicamente reemplazar un paquete por otro, según las condiciones que se cumplan al instalar. Esto elimina la necesidad de scripts posteriores a la instalación y proporciona un mecanismo de soporte de distribución de paquetes de primera clase.
Dota también ha introducido nuevas políticas y permisos, que te ayudan a restringir lo que los programas pueden y no pueden acceder en tiempo de ejecución. Específicamente en NPM, también se han realizado muchas mejoras en la auditoría. En NPM v8.16, lanzamos algo llamado Dependency Selector Synthesis. Este lenguaje se basa en gran medida en CSS. Contiene varios mecanismos de filtro redundantes similares a los que hemos tenido en el pasado y ayuda a crear un lenguaje que responde fácilmente a preguntas multifacéticas sobre tus dependencias y sus relaciones.
Aquí tienes algunos ejemplos de lo potente y expresivo que es este lenguaje. Puedes crear consultas similares a CSS para las dependencias utilizando el comando de consulta de NPM. Específicamente, puedes explorar los metadatos de tu paquete y solicitar cosas como paquetes con licencias específicas que deseas o no deseas, o versiones específicas que pueden o no cumplir con tus heurísticas específicas. Los atributos también están disponibles a través de la sintaxis del selector, al igual que los metadatos sobre el tipo de dependencia que es. En el último ejemplo, en realidad buscamos cualquier paquete o dependencia que tenga algún script de instalación, creando así una consulta para encontrar cualquier referencia mutable potencial dentro de nuestro gráfico de dependencias.
Al igual que en el navegador, hemos puesto esta sintaxis a disposición a través de un método que se basa en un árbol de dependencias de arborist. El método se llama QuerySelectorAll, que debería resultar familiar para los desarrolladores front-end. Si quieres probar la sintaxis del selector, puedes hacerlo ejecutando el comando npm query y proporcionando un selector. En este ejemplo, estoy buscando cualquier dependencia que tenga una versión inferior a 1.0.0. Luego, paso eso a jq y hago algunas cosas divertidas mientras mapeo la versión y el nombre de la versión.
Esperamos que esta herramienta te ayude a encontrar errores de manera más efectiva, aislarlos dentro del gráfico y asegurarte de entender qué se está instalando exactamente. Algunos selectores destacados que existen actualmente son cosas como samber y outdated. Aún no se han implementado, pero esperamos que pronto estén disponibles el estado vulnerable, así como los pseudo selectores CVE y CWE. Actualmente hay un RFC abierto para agregar consultas de auditoría al comando de auditoría de NPM. Esto te permitiría filtrar lo que te importa y si esas dependencias son vulnerables. Actualmente hay un RFC abierto llamado políticas de auditoría. Esta función te permite definir una sintaxis similar a ESLint para las políticas. Eligiendo un selector DSS junto con el tipo para el selector, mejorando las capacidades de auditoría que tenemos hoy y generalizando el cumplimiento de las heurísticas.
Entonces, ¿cuáles son los puntos clave de esta charla? La seguridad es un trabajo en equipo. Si necesitas un gestor de paquetes, probablemente deberías usar NPM. Mantener la curiosidad te mantendrá seguro y compartir los descubrimientos que encuentres nos beneficia a todos. Muchas gracias y mantente seguro.
Comments