Lecciones de SolarWinds: evaluación de bibliotecas de terceros

On By Jacob Emmert-Aronson10 Min Read
Lessons from SolarWinds – Evaluating third-party libraries

En diciembre de 2020, SolarWinds reveló que su producto Orion había sido objeto de un ataque a gran escala que, a su vez, concedió al atacante acceso a la infraestructura de muchos clientes de SolarWinds, entre los que se encontraban, sobre todo, varios organismos gubernamentales. El alcance de esta infracción hizo que se preste mucha atención a las vulnerabilidades de la cadena de suministro y al papel de las dependencias de terceros en la seguridad de un sistema de software. Si bien ninguna de estas amenazas es nueva, el escrutinio adicional llevado a esta área por los eventos actuales dejó a las organizaciones con un fuerte deseo de mejorar su postura de seguridad con la esperanza de no ser el próximo objetivo. Como equipo de ingeniería de software, su interacción más habitual con la cadena de suministro es la elección de las bibliotecas externas que se incorporan a sus aplicaciones.

Una biblioteca externa bien mantenida puede ser una gran ayuda para los esfuerzos de desarrollo, ya que ahorra innumerables horas de tiempo de ingeniería al permitirle concentrarse en los diferenciadores centrales de su propio producto en lugar de tener que volver a implementar una funcionalidad común. Por el contrario, las bibliotecas mal implementadas pueden ser difíciles de usar, introducir vulnerabilidades de seguridad que crean riesgos para su organización y sus clientes o, en casos extremos, incluso interferir con el funcionamiento de partes no relacionadas de su servicio o socavar toda su arquitectura. A continuación, resumiré muchas de las consideraciones que he utilizado para evaluar las bibliotecas en cuanto a la solidez de sus prácticas de ingeniería y sus posibles consecuencias de seguridad. Ofrezco estos enfoques como un punto de partida, no como una receta. Encuentre un enfoque que satisfaga sus propias necesidades. Si bien no hay soluciones mágicas en este espacio, asegurarse de que su proyecto se base solo en dependencias de alta calidad puede reducir sustancialmente su superficie de ataque y hacer que su producto sea más fácil de expandir y mantener.

Alcance de la biblioteca

Esta consideración inicial es clave porque determina hasta qué punto es necesaria o adecuada una evaluación. ¿Qué nivel de funcionalidad ofrece la biblioteca? ¿Qué importancia tiene esta funcionalidad para el funcionamiento de su producto? Una biblioteca simple con una superficie pequeña requiere mucho menos escrutinio que un marco grande que se integrará estrechamente en su propio código. Además, algunos indicadores que serían señales de alarma importantes para la funcionalidad clave (por ejemplo, las actualizaciones poco frecuentes) pueden ser normales o esperables para las bibliotecas más pequeñas que solo intentan cumplir una tarea extremadamente limitada.

Una pregunta relacionada es cómo piensa utilizar la biblioteca. Las dependencias de desarrollo (por ejemplo, una herramienta de análisis estático o un componente de un marco de pruebas unitarias) presentan mucho menos riesgo que las dependencias de tiempo de ejecución. Aunque los fallos en el proceso de compilación pueden retrasar una versión o causar otros problemas a corto plazo para los desarrolladores, no afectan directamente al usuario y, por lo general, no suponen un riesgo para la seguridad de la propia aplicación.

Historial de mantenimiento

La forma más rápida de hacerse una idea del estado general de un proyecto es mirar su historial de control de fuentes. ¿Cuándo fue la última versión? ¿Con qué frecuencia se publican las versiones y cuál es el índice de confirmaciones en el repositorio de código fuente? Me gusta ver proyectos que se actualizan con frecuencia porque eso me da más confianza en que la biblioteca seguirá manteniéndose en el futuro. Por el contrario, un proyecto que ha permanecido inactivo durante mucho tiempo puede contener errores no resueltos o puede introducir problemas de compatibilidad con las nuevas versiones de las dependencias comunes o incluso con el propio tiempo de ejecución del lenguaje.

También es sumamente valioso consultar el registro de cambios de una biblioteca. A veces, los cambios introducidos por cada versión se describen en la página de versiones. Otras veces, el registro de cambios es un archivo en el nivel superior del repositorio de código fuente. Si esta información no está fácilmente disponible, es una señal de alarma importante. Busco descripciones claras de lo que ha cambiado de una versión a otra y que cualquier incompatibilidad con versiones anteriores esté claramente documentada. Sin embargo, una alta frecuencia de cambios incompatibles con versiones anteriores o correcciones de errores en la funcionalidad central es en sí mismo motivo de preocupación, ya que esto sugiere que el desarrollador no hace un buen trabajo de planificación y depuración de los cambios antes del lanzamiento.

Relaciones con los encargados de mantenimiento

Una evaluación más exhaustiva podría consistir en examinar el registro de problemas de un proyecto y otros canales de comunicación pública. ¿Cómo responden los encargados de mantenimiento a los usuarios? ¿Son amables y receptivos a los comentarios, o suelen adoptar un tono más combativo? ¿Cuál es la proporción de problemas abiertos y cerrados? ¿Los encargados de mantenimiento abordan activamente las preocupaciones de los usuarios o los informes de errores permanecen inactivos durante largos períodos? ¿Cuán exhaustiva es la documentación y en qué medida orienta al usuario hacia las mejores prácticas de implementación? ¿Hay indicios de una comunidad vibrante en torno a este proyecto? Por ejemplo, ¿la carga de la asistencia a los usuarios recae enteramente en el encargado de mantenimiento principal, o hay otros miembros de la comunidad dispuestos a asumir parte de la carga y capaces de hacerlo? Un proyecto que mantiene una relación positiva con su comunidad tiene muchas más posibilidades de satisfacer las necesidades específicas de los usuarios y de adaptarse rápidamente a un entorno cambiante.

Dependencias transitivas

Esta evaluación requiere un poco más de esfuerzo que el simple recuento de la frecuencia de las versiones, pero proporciona información valiosa. Lo primero que quiero entender es en cuántas dependencias adicionales se basa una biblioteca, en particular, si incorpora dependencias innecesariamente. Las dependencias que proporcionan una funcionalidad clave para una biblioteca son mucho menos preocupantes que la incorporación de muchas bibliotecas adicionales para tareas no relacionadas. Cada dependencia adicional supone una complejidad añadida y un riesgo adicional para la cadena de suministro. En caso de duda, una sencilla herramienta de evaluación es instalar la biblioteca en un contenedor de Docker y observar cuántas bibliotecas adicionales se añaden en el proceso.

La mayor preocupación en esta categoría es la facilidad con la que podemos actualizar las dependencias a medida que se descubren nuevas vulnerabilidades. Por esta razón, una parte importante de la evaluación es señalar si una dependencia es restrictiva (solo se puede satisfacer con una versión específica de una biblioteca) o permisiva (se puede satisfacer con un rango de versiones). Las dependencias restrictivas son una preocupación importante porque pueden dificultar los esfuerzos de colocación de parches o incluso forzar que las bibliotecas de las que dependemos para otras funcionalidades vuelvan a una versión anterior. También es relevante la vigencia de estas dependencias transitivas. Una dependencia versionada que especifica una versión de hace dos meses es mucho menos preocupante que una dependencia de una versión de hace dos años. Del mismo modo, un signo de un proyecto bien gestionado es un historial de actualizaciones frecuentes que mantienen sus dependencias al día.

Dependencias entre lenguajes

Tenga especial cuidado con los paquetes escritos en un lenguaje con dependencias adicionales en un lenguaje diferente (por ejemplo, bibliotecas de Python con extensiones C compiladas). Si las dependencias secundarias implican un lenguaje o un entorno de programación con el que está menos familiarizado, será más difícil evaluar su calidad general. Además, los diferentes lenguajes suelen tener distintas convenciones de empaquetado, y los encargados de mantenimiento de los proyectos de lenguajes mixtos no suelen conocer las mejores prácticas de todos los lenguajes de programación con los que trabajan, lo que dificulta aún más la aplicación de parches y las actualizaciones.

Bibliotecas criptográficas

Las bibliotecas criptográficas merecen una consideración especial debido a la complejidad algorítmica implicada y al alto impacto de las posibles vulnerabilidades en este espacio. Examine estas bibliotecas con especial cuidado y asegúrese de solo confiar en bibliotecas revisadas a fondo y con un largo historial. Algunas opciones seguras son OpenSSL para C y C++, BouncyCastle para Java y la biblioteca de criptografía de PyCA para Python. Sus opciones pueden estar restringidas por la política de seguridad de su organización o los requisitos de cumplimiento. Sea consciente de las vulnerabilidades conocidas en las bibliotecas criptográficas y manténgase informado de las nuevas versiones. De todas las dependencias de terceros, estas son las que tienen mayor impacto en la seguridad.

Calidad del código y la documentación

Esta sección y la siguiente son evaluaciones de alto esfuerzo, pero este nivel de escrutinio, a veces, se justifica en casos de mayor riesgo. Cuando quiero hacerme una idea de la calidad general del código de un proyecto, trato de buscar el código fuente que utiliza una funcionalidad que ya comprendo profundamente y evalúo lo bien que han escrito esa pequeña área de su código base. A veces, examino la calidad de la documentación del proyecto, y me centro en la claridad y la capacidad del redactor para comunicar eficazmente conceptos complejos. En cualquier caso, el objetivo es determinar si los encargados de mantenimiento muestran una gran atención al detalle o, por el contrario, tienden a tomar atajos. La expectativa es que el grado de atención mostrado en una parte del proyecto sea probablemente representativo del estado del conjunto.

Como ejemplo concreto, si he elegido mirar el manejo de SSL de un proyecto de Python, podría notar lo siguiente:

  • ¿Utilizan los parámetros de conexión SSL predeterminados o intentan personalizarlos con una configuración más segura?
  • Si hacen personalizaciones, ¿qué tan sensibles son los cambios?
  • ¿Permiten al usuario realizar personalizaciones adicionales?
  • Si permiten personalizaciones, ¿reutilizan los objetos SSLContext de la biblioteca estándar de Python o intentan reinventar la rueda?

En una evaluación como esta, quiero ver principios de diseño sólidos, la reutilización de modismos estándar y que el autor pueda prever las posibles necesidades de los usuarios y proporcionar la extensibilidad adecuada para abordarlas.

Manejo de vulnerabilidades

He enumerado esto último porque suele ser una impresión que construyo con el tiempo y puede ser menos útil para una evaluación inicial. También depende, en gran medida, de la amplitud del uso y de la importancia de la seguridad de una biblioteca concreta. Sin embargo, esto puede ser, sin duda, un factor a la hora de decidir si se sigue utilizando una biblioteca existente o se intenta migrar a una que la sustituya.

En pocas palabras, trato de evaluar la capacidad de respuesta del encargado de mantenimiento del proyecto a la hora de colocar parches a las vulnerabilidades y lo fácil que es obtener los beneficios de esos parches en nuestras propias implementaciones. Un proyecto que con frecuencia está sujeto a divulgaciones de vulnerabilidades es algo preocupante, pero podría fácilmente ser un factor de uso generalizado y relevancia para la seguridad más que la calidad general del código y las prácticas de mantenimiento. Una mejor métrica es lo que sucede después de que se conoce una vulnerabilidad. ¿Se incorporan rápidamente los parches a las nuevas versiones? ¿Qué tan fácil es hacer actualizaciones una vez que se lanzan las versiones con parches? Si el proyecto, a menudo, realiza cambios radicales, especialmente si rompen regularmente la compatibilidad con versiones anteriores, ¿hacen modificaciones a las versiones anteriores? Si la biblioteca forma parte de una distribución de Linux, la responsabilidad de aplicar los parches suele recaer en los encargados de mantenimiento de la distribución y no en el desarrollador original, pero las mismas preguntas pueden aplicarse a la forma en la que el empaquetador maneja la biblioteca (las distribuciones suelen distinguir entre los paquetes principales con mantenimiento activo y los paquetes más periféricos, que suelen realizar un seguimiento de las versiones anteriores con cambios mínimos aplicados).

Cuando una biblioteca muestra un historial claro de manejo deficiente de las vulnerabilidades o funciona de un modo que dificulta el aprovechamiento de los parches de seguridad, suelo recomendar a mi equipo que migre a un sustituto.

Reflexiones finales

La evaluación de la calidad global de un proyecto de software y de la comunidad que lo rodea es una habilidad fundamental que será más relevante a medida que los proyectos de software sean más interdependientes. También es una habilidad muy individual; a menudo, obtendrá el mayor provecho de la investigación de las decisiones que toman los encargados de mantenimiento de las bibliotecas dentro de sus áreas de experiencia. Dado que la validación completa de cada detalle de un posible proveedor es una tarea aún más difícil que la creación de la funcionalidad por parte de uno mismo, el proceso de evaluación consiste en establecer un grado de confianza y adoptar medidas para garantizar que esa confianza no se pierda. En última instancia, aprender a examinar las dependencias de terceros es un componente importante de la creación de una cultura de ingeniería que se hace cargo de la seguridad y la confiabilidad de su producto.

Sobre el autor

Jacob Emmert-Aronson es ingeniero sénior del equipo de MindMeld, que forma parte de la organización Webex Intelligence. Es un líder del conocimiento en seguridad de la información, DevOps y mantenimiento de software, y su especialidad es entender cómo se relacionan estos temas

¿Está interesado en unirse al equipo de MindMeld? ¡Envíe un correo a mindmeld-jobs@cisco.com!

Regístrese en Webex

Visite nuestra página de inicio o póngase en contacto con nosotros directamente para obtener ayuda.


Haga clic aquí para obtener más información sobre las ofertas de Webex y para inscribirse en una cuenta gratuita. 

About The Author

Jacob Emmert-Aronson
Jacob Emmert-Aronson Senior Engineer Cisco
Jacob Emmert-Aronson is a senior engineer on the Mindmeld team, part of the Webex Intelligence organization.
Learn more

Topics


More like this