Un marco para cambiar la discusión en torno a las vulnerabilidades en el código abierto




Resumen ejecutivo:

La seguridad del software de código abierto ha atraído legítimamente la atención de la industria, pero las soluciones requieren consenso sobre los desafíos y la cooperación en la ejecución. El problema es complejo y hay muchas facetas que cubrir: cadena de suministro, gestión de dependencias, identidad y canalizaciones de construcción. Las soluciones llegan más rápido cuando el problema está bien enmarcado; Proponemos un marco ("Conocer, prevenir, reparar") sobre cómo la industria puede pensar en las vulnerabilidades en áreas concretas y de código abierto para abordar primero, que incluyen:

  • Consenso sobre metadatos y estándares de identidad: Necesitamos consenso sobre los fundamentos para abordar estos complejos problemas como industria. Los acuerdos sobre los detalles de los metadatos y las identidades permitirán la automatización, reducirán el esfuerzo requerido para actualizar el software y minimizarán el impacto de las vulnerabilidades.
  • Mayor transparencia y revisión para software crítico: Para el software que es crítico para la seguridad, necesitamos acordar procesos de desarrollo que garanticen una revisión suficiente, eviten cambios unilaterales y conduzcan de manera transparente a versiones oficiales verificables y bien definidas.

El siguiente marco y objetivos se proponen con la intención de provocar un debate en toda la industria y el progreso sobre la seguridad del software de código abierto.


Debido a eventos recientes, el mundo del software adquirió una comprensión más profunda del riesgo real de ataques a la cadena de suministro. Software de código abierto debería ser menos riesgoso en el frente de la seguridad, ya que todo el código y las dependencias están al descubierto y disponibles para inspección y verificación. Y si bien eso es generalmente cierto, se supone que la gente realmente está mirando. Con tantas dependencias, no es práctico monitorearlas todas, y muchos paquetes de código abierto no están bien mantenidos.

Es común que un programa dependa, directa o indirectamente, de miles de paquetes y bibliotecas. Por ejemplo, Kubernetes ahora depende de unos 1000 paquetes. El código abierto probablemente hace Más uso de dependencias que de código cerrado y de una gama más amplia de proveedores; el número de entidades distintas en las que se debe confiar se puede muy alto. Esto hace que sea extremadamente difícil comprender cómo se usa el código abierto en los productos y qué vulnerabilidades pueden ser relevantes. Tampoco hay garantía de que lo que se construye coincida con el código fuente.

Dando un paso atrás, aunque los ataques a la cadena de suministro son un riesgo, la gran mayoría de las vulnerabilidades son mundanas y no intencionales: errores honestos cometidos por desarrolladores bien intencionados. Además, es más probable que los delincuentes aprovechen las vulnerabilidades conocidas que encuentren las suyas propias: es más fácil. Como tal, debemos centrarnos en realizar cambios fundamentales para abordar la mayoría de las vulnerabilidades, ya que hacerlo hará que toda la industria avance en el abordaje de los casos complejos también, incluidos los ataques a la cadena de suministro.

Pocas organizaciones pueden verificar todos los paquetes que utilizan, y mucho menos todas las actualizaciones de esos paquetes. En el panorama actual, rastrear estos paquetes requiere una cantidad no trivial de infraestructura y un esfuerzo manual significativo. En Google, tenemos esos recursos y hacemos todo lo posible para administrar los paquetes de código abierto que usamos, incluido el mantenimiento de un repositorio privado de todos los paquetes de código abierto que usamos internamente, y es todavía desafiante para rastrear todas las actualizaciones. El gran flujo de actualizaciones es abrumador. Una parte fundamental de cualquier solución será una mayor automatización, y este será un tema clave para nuestro trabajo de seguridad de código abierto en 2021 y más allá.

Debido a que este es un problema complejo que necesita la cooperación de la industria, nuestro propósito aquí es enfocar la conversación en torno a objetivos concretos. Google cofundó OpenSSF para ser un punto focal para esta colaboración, pero para avanzar, necesitamos la participación de toda la industria y un acuerdo sobre cuáles son los problemas y cómo podemos abordarlos. Para iniciar la discusión, presentamos una forma de enmarcar este problema y un conjunto de objetivos concretos que esperamos aceleren las soluciones para toda la industria.

Sugerimos enmarcar el desafío como tres áreas de problemas en gran medida independientes, cada una con objetivos concretos:

  1. Saber sobre las vulnerabilidades de su software
  2. Evitar la adición de nuevas vulnerabilidades, y
  3. Reparar o eliminar vulnerabilidades.

Un problema relacionado pero separado, que es fundamental para asegurar la cadena de suministro, es mejorar la seguridad del proceso de desarrollo. Hemos descrito los desafíos de este problema y los objetivos propuestos en la cuarta sección, Prevención para software crítico.

Conozca sus vulnerabilidades

Conocer sus vulnerabilidades es más difícil de lo esperado por muchas razones. Aunque existen mecanismos para informar las vulnerabilidades, es difícil saber si realmente afectan las versiones específicas del software que está utilizando.

Objetivo: datos precisos de vulnerabilidad

Primero, es crucial capturar metadatos de vulnerabilidad precisos de todas las fuentes de datos disponibles. Por ejemplo, saber qué versión introdujo una vulnerabilidad ayuda a determinar si el software de uno se ve afectado, y saber cuándo se corrigió da como resultado un parcheo preciso y oportuno (y una ventana reducida para una posible explotación). Idealmente, este flujo de trabajo de clasificación debería automatizarse.

En segundo lugar, la mayoría de las vulnerabilidades se encuentran en sus dependencias, en lugar del código que escribe o controla directamente. Por lo tanto, incluso cuando su código no cambia, puede haber una rotación constante en sus vulnerabilidades: algunas se corrigen y otras se agregan.1

Objetivo: esquema estándar para bases de datos de vulnerabilidad

Los estándares de la industria y la infraestructura son necesarios para rastrear y mantener las vulnerabilidades de código abierto, comprender sus consecuencias y administrar sus mitigaciones. Un esquema de vulnerabilidad estándar permitiría que las herramientas comunes funcionen en múltiples bases de datos de vulnerabilidades y simplificaría la tarea de seguimiento, especialmente cuando las vulnerabilidades tocan varios idiomas o subsistemas.

Objetivo: seguimiento preciso de las dependencias

Se necesitan mejores herramientas para comprender rápidamente qué software se ve afectado por una vulnerabilidad recién descubierta, un problema que se complica por la escala y la naturaleza dinámica de los grandes árboles de dependencia. Las prácticas actuales también dificultan a menudo predecir exactamente qué versiones se utilizan sin realizar una instalación, ya que el software para la resolución de versiones solo está disponible a través del instalador.

Prevenir nuevas vulnerabilidades

Sería ideal evitar que se creen vulnerabilidades y, aunque las herramientas de prueba y análisis pueden ayudar, la prevención siempre será un problema difícil. Aquí nos centramos en dos aspectos específicos:

  • Comprender los riesgos al decidir sobre una nueva dependencia
  • Mejora de los procesos de desarrollo de software crítico

Objetivo: comprender los riesgos de las nuevas dependencias

La primera categoría consiste esencialmente en conocer las vulnerabilidades en el momento en que decide utilizar un paquete. Asumir una nueva dependencia tiene un riesgo inherente y debe ser una decisión informada. Una vez que tiene una dependencia, generalmente se vuelve más difícil de eliminar con el tiempo.

Conocer las vulnerabilidades es un gran comienzo, pero podemos hacer más.

Muchas vulnerabilidades surgen de la falta de adherencia a las mejores prácticas de seguridad en los procesos de desarrollo de software. ¿Todos los colaboradores utilizan la autenticación de dos factores (2FA)? ¿El proyecto tiene una configuración de integración continua y pruebas en ejecución? ¿Está integrado el fuzzing? Estos son los tipos de controles de seguridad que ayudarían a los consumidores a comprender los riesgos que están asumiendo con las nuevas dependencias. Los paquetes con una "puntuación" baja merecen una revisión más detallada y un plan de remediación.

El recientemente anunciado Cuadros de mando de seguridad proyecto de OpenSSF intenta generar estos puntos de datos de forma totalmente automatizada. El uso de tarjetas de puntuación también puede ayudar a defenderse ataques de tipoquatting frecuentes (paquetes malévolos con nombres similares a los paquetes populares), ya que obtendrían puntuaciones mucho más bajas y fallarían muchos controles de seguridad.

Mejorar los procesos de desarrollo de software crítico está relacionado con la prevención de vulnerabilidades, pero merece su propia discusión más adelante en nuestra publicación.

Reparar o eliminar vulnerabilidades

El problema general de corregir vulnerabilidades está más allá de nuestro alcance, pero hay mucho que podemos hacer para el problema específico de administrar vulnerabilidades en dependencias de software. Hoy en día hay poca ayuda en este frente, pero a medida que mejoramos la precisión, vale la pena invertir en nuevos procesos y herramientas.

Una opción, por supuesto, es corregir la vulnerabilidad directamente. Si puede hacer esto de una manera compatible con versiones anteriores, entonces la solución está disponible para todos. Pero un desafío es que es poco probable que tenga experiencia en el problema, ni capacidad directa para realizar cambios. La reparación de una vulnerabilidad también supone que los encargados del mantenimiento del software son conscientes del problema y tienen el conocimiento y los recursos para la divulgación de la vulnerabilidad.

Por el contrario, si simplemente elimina la dependencia que contiene la vulnerabilidad, entonces se soluciona para usted y aquellos que importan o usan su software, pero no para nadie más. Este es un cambio que está bajo su control directo.

Estos escenarios representan los dos extremos de la cadena de dependencias entre su software y la vulnerabilidad, pero en la práctica pueden intervenir muchos paquetes. La esperanza general es que alguien a lo largo de esa cadena de dependencia lo solucione. Desafortunadamente, arreglar un vínculo no es suficiente: todos los vínculos de la cadena de dependencia entre usted y la vulnerabilidad deben actualizarse antes de que se solucione el software. Cada enlace debe incluir la versión fija de lo que se encuentra debajo para purgar la vulnerabilidad. Por lo tanto, las actualizaciones deben realizarse de abajo hacia arriba, a menos que pueda eliminar la dependencia por completo, lo que puede requerir actos heroicos similares y rara vez es posible, pero es la mejor solución cuando lo es.

Objetivo: comprender sus opciones para eliminar vulnerabilidades

Hoy en día, carecemos de claridad en este proceso: ¿qué avances han logrado otros y qué actualizaciones deben aplicarse a qué nivel? ¿Y dónde está atascado el proceso? ¿Quién es responsable de corregir la vulnerabilidad en sí? ¿Quién es responsable de propagar la solución?

Objetivo: notificaciones para acelerar las reparaciones

Con el tiempo, sus dependencias se solucionarán y podrá actualizar localmente a las nuevas versiones. Saber cuándo sucede esto es un objetivo importante ya que acelera la reducción de la exposición a vulnerabilidades. También necesitamos un sistema de notificación para el descubrimiento real de vulnerabilidades; A menudo, las nuevas vulnerabilidades representan problemas latentes que se descubren recientemente aunque el código real no haya cambiado (como este Vulnerabilidad de 10 años en la utilidad de Unix sudo). Para proyectos grandes, la mayoría de estos problemas surgirán en las dependencias indirectas. Hoy en día, carecemos de la precisión necesaria para hacer bien las notificaciones, pero a medida que mejoramos la precisión de las vulnerabilidades y los metadatos (como se indicó anteriormente), también deberíamos impulsar las notificaciones.

Hasta ahora, solo hemos descrito el caso fácil: una secuencia de actualizaciones que son compatibles con versiones anteriores, lo que implica que el comportamiento es el mismo excepto por la ausencia de la vulnerabilidad.

En la práctica, una actualización a menudo no es compatible con versiones anteriores o está bloqueada por restricciones versión requisitos. Estos problemas significan que la actualización de un paquete en lo más profundo del árbol de dependencias debe causar cierta rotación, o al menos actualizaciones de requisitos, en las cosas anteriores. La situación a menudo surge cuando la corrección se realiza a la última versión, digamos 1.3, pero su software o paquetes intermedios solicitan 1.2. Vemos esta situación a menudo, y sigue siendo un gran desafío que se hace aún más difícil por la dificultad de lograr que los propietarios actualicen los paquetes intermedios. Además, si usa un paquete en mil lugares, lo cual no es una locura para una gran empresa, es posible que deba pasar por el proceso de actualización mil veces.

Objetivo: corregir las versiones más utilizadas

También es importante corregir la vulnerabilidad en las versiones anteriores, especialmente las que se usan mucho. Dicha reparación es una práctica común para el subconjunto de software que tiene soporte a largo plazo, pero idealmente todas las versiones ampliamente utilizadas deben ser reparadas, especialmente por riesgos de seguridad.

La automatización podría ayudar: dada una corrección para una versión, tal vez podamos generar buenas correcciones candidatas para otras versiones. Este proceso a veces se realiza a mano hoy en día, pero si podemos hacerlo significativamente más fácil, más versiones serán parcheadas y habrá menos trabajo por hacer en la parte superior de la cadena.

En resumen, necesitamos formas de hacer que la reparación de vulnerabilidades, especialmente en dependencias, sea más fácil y más oportuna. Necesitamos aumentar las posibilidades de que haya una solución para las versiones más utilizadas y no solo para la última versión, que a menudo es difícil de adoptar debido a los otros cambios que incluye.

Por último, hay muchas otras opciones en el frente de la "reparación", que incluyen varios tipos de mitigaciones, como evitar ciertos métodos o limitar el riesgo a través de cajas de arena o controles de acceso. Estas son opciones prácticas importantes que necesitan más discusión y apoyo.

Prevención de software crítico

El marco anterior se aplica ampliamente a las vulnerabilidades, independientemente de si se deben a malos actores o simplemente a errores inocentes. Aunque los objetivos sugeridos cubren la mayoría de las vulnerabilidades, no son suficientes para prevenir comportamientos maliciosos. Para tener un impacto significativo en la prevención de los malos actores, incluidos los ataques a la cadena de suministro, debemos mejorar los procesos utilizados para el desarrollo.

Esta es una gran tarea, y actualmente poco realista para la mayoría de código abierto. Parte de la belleza del código abierto es su falta de restricciones en el proceso, lo que alienta a una amplia gama de contribuyentes. Sin embargo, esa flexibilidad puede obstaculizar las consideraciones de seguridad. Queremos colaboradores, pero no podemos esperar que todos estén igualmente enfocados en la seguridad. En cambio, debemos identificar los paquetes críticos y protegerlos. Estos paquetes críticos deben ajustarse a una variedad de estándares de desarrollo más altos, aunque eso podría agregar fricción al desarrollador.

Objetivo: definir criterios para proyectos de código abierto "críticos" que merezcan estándares más altos

Es importante identificar los paquetes "críticos" de los que todos dependemos y cuyo compromiso podría poner en peligro la infraestructura crítica o la privacidad del usuario. Estos paquetes deben ajustarse a estándares más altos, algunos de los cuales se describen a continuación.

No es obvio cómo definir "crítico" y es probable que la definición se amplíe con el tiempo. Más allá del software obvio, como OpenSSL o bibliotecas criptográficas clave, existen paquetes ampliamente utilizados donde su alcance hace que valga la pena protegerlos. Comenzamos el Proyecto Criticality Score para intercambiar ideas sobre este problema con la comunidad, así como colaborar con Harvard en los esfuerzos del censo de código abierto.

Objetivo: no realizar cambios unilaterales en el software crítico

Un principio que seguimos en Google es que los cambios no deben ser unilaterales, es decir, cada cambio involucra al menos a un autor y un revisor o aprobador. El objetivo es limitar lo que un adversario puede hacer por sí solo; debemos asegurarnos de que alguien realmente esté observando los cambios. Hacer esto bien para el código abierto es en realidad un poco más difícil que solo dentro de una sola empresa, que puede tener una autenticación sólida y hacer cumplir las revisiones de código y otras verificaciones.

Evitar cambios unilaterales se puede dividir en dos subobjetivos:

Objetivo: Requerir revisión de código para software crítico

Además de ser un gran proceso para mejorar el código, las revisiones aseguran que al menos una persona que no sea el autor esté observando cada cambio. Las revisiones de código son una práctica estándar para todos los cambios dentro de Google.

Objetivo: los cambios en el software crítico requieren la aprobación de dos partes independientes

Para lograr realmente el objetivo de "alguien está mirando", necesitamos que el revisor sea independiente del colaborador. Y para cambios críticos, probablemente queramos más de una revisión independiente. Necesitamos aclarar qué cuenta como revisión "independiente", por supuesto, pero la idea de independencia es fundamental para las revisiones en la mayoría de las industrias.

Objetivo: autenticación para participantes en software crítico

Cualquier noción de independencia también implica que conoces a los actores; no se puede suponer que un actor anónimo sea independiente o digno de confianza. Hoy en día, esencialmente tenemos seudónimos: la misma persona usa una identidad repetidamente y, por lo tanto, puede tener una reputación, pero no siempre conocemos la confiabilidad del individuo. Esto conduce a una variedad de subobjetivos:

Objetivo: para el software crítico, los propietarios y encargados del mantenimiento no pueden ser anónimos

A los atacantes les gusta mantener el anonimato. Ha habido ataques anteriores a la cadena de suministro en los que los atacantes aprovecharon el anonimato y se abrieron camino a través de comunidades de paquetes para convertirse en mantenedores, sin que nadie se diera cuenta de que este "nuevo mantenedor" tenía intenciones maliciosas (el código fuente comprometido finalmente se inyectó en sentido ascendente). Para mitigar este riesgo, nuestra opinión es que los propietarios y mantenedores de software crítico no deben ser anónimos.

Es concebible que los colaboradores, a diferencia de los propietarios y mantenedores, puedan ser anónimos, pero solo si su código ha pasado varias revisiones por parte de personas de confianza.

También es concebible que podamos tener identidades “verificadas”, en las que una entidad de confianza conoce la identidad real, pero por razones de privacidad el público no. Esto permitiría tomar decisiones sobre la independencia, así como el enjuiciamiento por comportamiento ilegal.

Objetivo: Autenticación sólida para los colaboradores de software crítico

Los actores maliciosos buscan vectores de ataque fáciles, por lo que los ataques de phishing y otras formas de robo relacionadas con las credenciales son comunes. Una mejora obvia sería el uso requerido de la autenticación de dos factores, especialmente para propietarios y mantenedores.

Objetivo: un modelo federado de identidades

Para continuar con la naturaleza inclusiva del código abierto, necesitamos poder confiar en una amplia gama de identidades, pero aún con integridad verificada. Esto implica un modelo federado para las identidades, tal vez similar a cómo admitimos los certificados SSL federados en la actualidad: una variedad de grupos pueden generar certificados válidos, pero con una sólida auditoría y supervisión mutua.

Discusiones sobre este tema están comenzando a tener lugar en el OpenSSF Grupo de trabajo de certificación de identidad digital.

Objetivo: notificación de cambios en el riesgo

Deberíamos ampliar las notificaciones para cubrir los cambios de riesgo. El más obvio son los cambios de propiedad, que pueden ser un preludio de nuevos ataques (como el reciente NPM compromiso de flujo de eventos). Otros ejemplos incluyen el descubrimiento de credenciales robadas, colusión u otro mal comportamiento de actor.

Objetivo: transparencia de los artefactos

Es común utilizar hashes seguros para detectar si un artefacto ha llegado intacto y firmas digitales para demostrar su autenticidad. Agregar "transparencia" significa que estas certificaciones se registran públicamente y, por lo tanto, documentan lo que se pretendía. A su vez, las partes externas pueden monitorear los registros en busca de versiones falsas incluso si los usuarios no lo saben. Yendo un paso más allá, cuando se roban las credenciales, podemos saber qué artefactos se firmaron con esas credenciales y trabajar para eliminarlos. Este tipo de transparencia, incluidos los registros públicos duraderos y el monitoreo de terceros, se ha utilizado con gran éxito para Certificados SSL, y tenemos propuesto una forma de hacer esto para los administradores de paquetes. Saber que tiene el paquete o binario correcto es similar a saber que está visitando la versión real de un sitio web.

Objetivo: confiar en el proceso de construcción

Premio Turing de Ken Thompson conferencia demostró en 1984 que el código fuente auténtico por sí solo no es suficiente, y eventos recientes han demostrado que este ataque es una amenaza real. ¿Cómo confía en su sistema de construcción? Todos los componentes deben ser confiables y verificados a través de un proceso continuo de generación de confianza.

Las compilaciones reproducibles ayudan (hay un resultado determinista para la compilación y, por lo tanto, podemos verificar que lo hicimos bien), pero son más difíciles de lograr debido a que los datos efímeros (como las marcas de tiempo) terminan en el artefacto de lanzamiento. Y las construcciones reproducibles seguras requieren herramientas de verificación, que a su vez deben construirse de manera verificable y reproducible, y así sucesivamente. Debemos construir una red de herramientas confiables y crear productos.

La confianza tanto en los artefactos como en las herramientas se puede establecer mediante la "delegación", a través de una variante del proceso de transparencia descrito anteriormente llamado autorización binaria. Internamente, el sistema de compilación de Google firma todos los artefactos y produce un manifiesto que lo vincula al código fuente. Para el código abierto, uno o más agentes confiables podrían ejecutar la compilación como un servicio, firmando el artefacto para demostrar que son responsables de su integridad. Este tipo de ecosistema debería existir y sobre todo necesita conciencia y algunos acuerdos sobre el formato de las atestaciones, para que podamos automatizar los procesos de forma segura.

Las acciones de esta sección son excelentes para el software en general y, en esencia, se utilizan hoy en día en Google, pero son más pesadas de lo habitual para el código abierto. Nuestra esperanza es que al enfocarnos en el subconjunto de software que es crítico, podamos lograr estos objetivos al menos para ese conjunto. A medida que mejoren las herramientas y la automatización, estos objetivos serán más fáciles de adoptar de manera más amplia.

Resumen

La naturaleza del código abierto requiere que resolvamos problemas a través del consenso y la colaboración. Para temas complejos como las vulnerabilidades, esto implica una discusión enfocada en torno a los temas clave. Presentamos una forma de enmarcar esta discusión y definimos un conjunto de objetivos que esperamos aceleren el discurso en toda la industria y las soluciones definitivas. El primer conjunto de objetivos se aplica ampliamente a las vulnerabilidades y realmente se trata de permitir la automatización y reducir el riesgo y el esfuerzo.

Sin embargo, estos objetivos no son suficientes en presencia de adversarios o para prevenir ataques a la "cadena de suministro". Por tanto, proponemos un segundo conjunto de objetivos para el software crítico. El segundo conjunto es más oneroso y, por lo tanto, encontrará cierta resistencia, pero creemos que las restricciones adicionales son fundamentales para la seguridad. La intención es definir colectivamente el conjunto de paquetes de software "críticos" y aplicar estos estándares más altos solo a este conjunto.

Aunque tenemos varias opiniones sobre cómo cumplir con ambos conjuntos de objetivos, somos una sola voz en un espacio donde el consenso y las soluciones sostenibles son lo más importante. Esperamos con interés esta discusión, promover las mejores ideas y, finalmente, soluciones que fortalezcan y agilicen la seguridad del código abierto de la que todos dependemos.

Notas



Enlace a la noticia original