Ahora, cada vez más personas hablan sobre el análisis estático para buscar vulnerabilidades como una etapa necesaria del desarrollo. Sin embargo, muchos hablan sobre los problemas del análisis estático. Hablamos mucho sobre esto en los últimos
días de Hack Positivo , y en base a los resultados de estas discusiones,
ya escribimos sobre cómo funciona el analizador estático. Si probaste alguna herramienta seria, podrías asustarte con informes largos con recomendaciones confusas, dificultades para configurar la herramienta y falsos positivos. Entonces, ¿todavía se necesita un análisis estático?
Nuestra experiencia sugiere lo que se necesita. Y muchos de los problemas que surgen cuando miras por primera vez la herramienta, es bastante posible de resolver. Trataré de decirle lo que el usuario puede hacer y cómo debería ser el analizador para que su uso sea útil y no presente "otra herramienta innecesaria que el personal de seguridad requiere".
Sobre el análisis estático
Entonces, ya hemos hablado sobre las limitaciones teóricas del análisis estático. Por ejemplo, el análisis estático profundo intenta resolver problemas que son exponenciales en complejidad. Por lo tanto, cada herramienta busca un compromiso entre el tiempo que lleva, los recursos gastados, la cantidad de vulnerabilidades encontradas y la cantidad de falsos positivos.
¿Por qué necesitamos un análisis en profundidad? Cualquier IDE encuentra errores muy rápidamente, a veces incluso los relacionados con la seguridad: ¿cuáles son generalmente problemas exponenciales? Un ejemplo clásico es la inyección SQL (y cualquier otra inyección, como XSS, RCE y similares), que pasa a través de varias funciones (es decir, la lectura de datos del usuario y la ejecución de la consulta ocurren en diferentes funciones). Su búsqueda requiere un análisis interprocedural del flujo de datos, y esta es una tarea de complejidad exponencial. De acuerdo, sin buscar tales vulnerabilidades, el análisis no puede considerarse profundo. Por la misma razón, debe analizar el código en su totalidad, y no en partes; de lo contrario, se podrían perder vulnerabilidades interprocediales.
En los últimos años, he adquirido mucha experiencia en la comunicación con clientes (potenciales) de varios analizadores estáticos. En particular, discutimos los reclamos a las herramientas basados en los resultados del primer uso (piloto). La mayoría de las afirmaciones se derivan de una forma u otra de las limitaciones teóricas de la tecnología. Además, las herramientas pueden simplemente no tener la funcionalidad que el usuario necesita. Sin embargo, en mi opinión, los analizadores pueden moverse (y se están moviendo) hacia el usuario en términos de resolver los problemas que se indican a continuación. Pero también debe poder usar analizadores, nivelando las consecuencias de los mismos problemas, ya que resulta que esto no es tan difícil. Vamos en orden.
Puedes imaginar una situación modelo: decides probar la tecnología en acción o elegir un analizador estático, gasta un piloto. Por supuesto, no confía en los casos de prueba del proveedor y desea intentar analizar su código (al mismo tiempo, puede encontrar vulnerabilidades reales y corregirlas). Se le proporciona un instalador o una máquina virtual terminada con un sistema por un corto tiempo.
Ejecutar análisis
Primero necesitas ejecutar el análisis. Usted va a la interfaz y todo parece estar claro: cargue el archivo con el código fuente en el formulario y haga clic en "analizar". Pero no: obtienes varios formularios con diferentes campos que deben completarse de alguna manera. Es necesario especificar lenguajes de programación, algunos ajustes del analizador, seleccionar paquetes de vulnerabilidad (¿cómo sabe qué se incluye en ellos?) Y así sucesivamente. Pasa esta prueba y comienza el análisis. Ah, no, un error de escaneo. “El formato no cumple con los requisitos”, “Se requiere un ensamblaje de código para este idioma”, “No se encontraron archivos para escanear” ... Si no escribió este código usted mismo, aún tendrá que acudir a los desarrolladores para obtener ayuda.
El desarrollador entrega el código fuente para probarSe presta especial atención a los requisitos para el código de construcción. La mayoría de los analizadores para varios idiomas requieren que el código se recopile durante el análisis (lenguajes JVM: Java, Scala, Kotlin y similares, C / C ++, Objective-C, C #). Entiende lo doloroso que es: reproducir el entorno de un gran proyecto para ensamblar en una nueva máquina. Por otro lado, estos requisitos están justificados; se desprenden de la tecnología de análisis y los detalles de estos lenguajes.
¿Cómo resuelven estos analizadores estos problemas? En primer lugar, hacen que el lanzamiento del análisis sea lo más automatizado posible. Idealmente, es suficiente descargar un archivo de cualquier formato, y el analizador mismo debe comprender qué idiomas hay, cómo intentar compilar y cómo configurar el resto de las configuraciones de forma predeterminada para que los resultados sean lo más completos posible. Está claro que es imposible prever todo; sin embargo, puede tratar de manejar la mayoría de los casos.
Los requisitos de montaje deben hacerse lo más suaves posible. Por ejemplo, para los lenguajes JVM, no necesita requerir el ensamblaje durante el análisis; solo solicite cargar artefactos, es decir, el código ensamblado junto con las fuentes (que es mucho más simple). Para Xcode, en el caso de Objective-C, el ensamblaje se puede automatizar para la mayoría de los casos. Si no fue posible recopilar el código, el analizador puede intentar realizar un análisis parcial. Sus resultados no serán tan completos, pero es mejor que ningún resultado. También es conveniente si el módulo de análisis se puede colocar en la máquina para el desarrollador, donde el ensamblaje del código ya está configurado, mientras que la arquitectura debe permitir que los otros módulos y la parte de la interfaz se transfieran a otra máquina.
Finalmente, el analizador debe presentar los requisitos de formato más suaves y ocuparse de los archivos de entrada en sí. Un archivo con código fuente, archivos anidados, un archivo de un repositorio, un enlace a un repositorio, un archivo de un producto, un archivo ejecutable de un producto: es bueno si el analizador admite todo esto.
Sin embargo, no olvide que el analizador no tiene inteligencia artificial y no puede prever todo. Por lo tanto, si se producen errores, debe familiarizarse con el manual; hay muchas cosas útiles para preparar el código para el análisis. Bueno, todo este trabajo de lanzar un escaneo durante la implementación del analizador se realiza solo una vez para cada base de código. Muy a menudo, el analizador generalmente está integrado en el ciclo de CI, es decir, no habrá problemas con el ensamblaje.
Proceso de análisis
Bien, el escaneo ha comenzado. Pasa una hora, sin resultados. La barra de progreso se cuelga en algún lugar en el medio, no está claro con qué porcentaje y qué pronóstico se completa. La segunda hora pasa: el progreso se ha movido un 99 por ciento y ha estado suspendido allí durante media hora. La tercera hora pasa y el analizador se bloquea, informando una falta de RAM. O cuelga otra hora y termina. Puede esperar que el análisis pase a la misma velocidad que su estilo de verificación, y aquí las expectativas diferirán enormemente de la realidad.

Sí, un buen analizador estático puede consumir muchos recursos, señalé una de las razones anteriores: encontrar vulnerabilidades complejas es una tarea exponencialmente difícil. Entonces, cuantos más recursos haya y más tiempo, mejores serán los resultados (con un buen motor, por supuesto). Es realmente difícil predecir tanto el tiempo de análisis como los recursos requeridos: el tiempo de operación de los algoritmos de análisis estático depende en gran medida de las construcciones del lenguaje, de la complejidad del código, de la profundidad de las llamadas, de las características que son difíciles de calcular de antemano.
El problema con los recursos es un mal necesario. Debe tener cuidado con la asignación de los recursos necesarios, esperar pacientemente a que finalice el escaneo y también comprender que nadie puede predecir con precisión los recursos necesarios para el analizador, incluso con una base de código determinada, y debe estar preparado para cambiar estos parámetros. Además, los parámetros requeridos pueden cambiar incluso sin actualizar la base del código, debido a la actualización del analizador.
Sin embargo, el analizador puede ayudar un poco con este problema. Es capaz de separar la parte que consume muchos recursos (motores) y la interfaz en diferentes máquinas. Esto le permitirá no cargar máquinas con programas innecesarios que ralentizarán su trabajo, mientras que será posible utilizar la interfaz del sistema para cualquier carga de trabajo en los escaneos (por ejemplo, para ver y editar resultados). Esto también facilitará la escala sin reinstalar todo el sistema (elevamos el analizador en una nueva máquina virtual, especificamos la IP de la máquina principal, y listo).
Además, el analizador puede permitirle elegir la profundidad de análisis, deshabilitar verificaciones pesadas, usar análisis incremental (en el que no se verifica todo el código, sino que solo se modifica). Estas cosas deben usarse con mucho cuidado, ya que pueden afectar en gran medida los resultados del análisis. Si utiliza dicha funcionalidad, se recomienda realizar un análisis completo en algunos intervalos.
Resultados de analisis
Pasemos a los resultados del escaneo (durante mucho tiempo fuimos a ellos). Esperas la cantidad de vulnerabilidades en la ventana del analizador con inquietud, y estás muy sorprendido de verlo. 156 críticas, 1260 medias y 3210 bajas. Ir a la página de resultados y ahogarse en la cantidad de problemas encontrados. Descarga un informe en pdf y ve varios miles de páginas de texto. ¿Adivina qué dirá el desarrollador del código cuando vea un lienzo así?
El guardia de seguridad está llevando un informe de vulnerabilidad al desarrollador.Pero sigamos intentando ver los resultados, dale una oportunidad. Después de examinar cuidadosamente docenas de ocurrencias, comienza a comprender por qué hay tantas vulnerabilidades. Varias vulnerabilidades realmente parecen ser serias, entiendes que necesitan ser reparadas. Sin embargo, inmediatamente te encuentras con una docena de falsos. Y también: una gran cantidad de vulnerabilidades en el código de las bibliotecas. ¡No corregirá las bibliotecas! Y luego comprende cuánto tiempo pasará analizando los resultados. Y este procedimiento debe repetirse todos los días, semanas, bien, o al menos cada lanzamiento. (En realidad no).
Para empezar, los falsos positivos se pueden entender de maneras muy diferentes. Alguien no considerará falsa solo vulnerabilidades críticas que pueden explotarse en este momento. Alguien considerará falso solo los errores explícitos del analizador. Mucho depende de lo que quieras de la herramienta. Recomendamos que considere casi todos los sucesos, ya que incluso una vulnerabilidad de bajo nivel que no puede ser explotada ahora puede convertirse en un problema grave mañana, por ejemplo, debido a cambios en el código y condiciones externas.
Ok, debes mirar todas las entradas, pero esto sigue siendo una gran cantidad de trabajo. Y aquí los analizadores pueden ayudar muy bien. La función más importante del analizador es la capacidad de rastrear las vulnerabilidades entre los escaneos de un proyecto, mientras que el seguimiento es resistente a los pequeños cambios que son estándar para el desarrollo del código. Esto elimina el problema de que es necesario repetir un largo análisis de vulnerabilidades: la primera vez que pasa más tiempo, elimina los falsos positivos y cambia la importancia de los sucesos, pero luego solo tendrá que buscar nuevas vulnerabilidades, que serán varias veces más pequeñas.
Bien, pero ¿es necesario revisar todas las vulnerabilidades por primera vez? Recomendamos hacer esto, pero en general, esto no es necesario. En primer lugar, los analizadores le permiten filtrar los resultados por directorios y archivos: por ejemplo, cuando inicia un análisis, puede excluir inmediatamente cualquier componente, biblioteca o código de prueba del análisis. Esto afectará la velocidad del análisis. En segundo lugar, los analizadores le permiten filtrar los resultados por vulnerabilidades, es decir, cuando comienza a escanear, puede limitar el conjunto de vulnerabilidades. Finalmente, además de la criticidad, el analizador puede producir algo así como la probabilidad de una falsa vulnerabilidad (es decir, su confianza en esta vulnerabilidad). Usando esta métrica, puede filtrar los resultados.
Por separado, vale la pena señalar la tecnología de análisis de composición de software (ahora está comenzando a ser compatible con un número creciente de instrumentos en diferentes niveles). La tecnología le permite detectar el uso de bibliotecas en su código, determinar los nombres y versiones, mostrar vulnerabilidades conocidas, así como licencias. Esta tecnología puede separar el código de la biblioteca del suyo, que también puede filtrar los resultados.
Resulta que puedes lidiar con el problema de los abundantes resultados de análisis, y esto no es muy difícil. Y aunque la primera visualización de los resultados puede llevar algo de tiempo, cuando la escanea, se gastará cada vez menos. Sin embargo, vuelvo a señalar que debe tener cuidado con cualquier filtrado de resultados; puede omitir la vulnerabilidad. Incluso si se conoce la biblioteca, no significa que no haya vulnerabilidad en ella. Si ahora esta vulnerabilidad se detecta mal (es decir, la herramienta muestra muchos falsos positivos para esta vulnerabilidad), y la deshabilita, al actualizar el analizador, puede omitir la vulnerabilidad real.
Revisa el analizador
Entendido con un gran informe y falsos positivos. Pero desea ir más allá: para asegurarse de que el analizador encuentre aquellas vulnerabilidades de las que está seguro (podría haberlas establecido intencionalmente o haber encontrado otra herramienta).

Para empezar, es importante comprender que el analizador no pudo encontrar la vulnerabilidad por varias razones. Lo más simple es que la exploración se configuró incorrectamente (debe prestar atención a los mensajes de error). Pero desde el punto de vista de la tecnología de análisis, los motivos pueden ser diferentes. Un analizador estático consta de dos componentes importantes: un motor (contiene toda la complejidad algorítmica y matemática) y una base de reglas de búsqueda de vulnerabilidad. Una situación es cuando el motor le permite encontrar una vulnerabilidad de esta clase, pero no hay vulnerabilidad en la base de reglas. En este caso, agregar una regla generalmente no es difícil. Una situación completamente diferente, si el motor, en principio, no soporta tales vulnerabilidades, aquí la revisión puede ser muy significativa. Di un ejemplo al principio del artículo: la inyección SQL nunca se puede encontrar sin algoritmos de análisis de flujo de datos.
Un analizador estático debe implementar un conjunto de algoritmos en el motor que cubra las clases de vulnerabilidades disponibles para un lenguaje de programación dado (análisis de flujo de control, flujo de datos, análisis de intervalos, etc.). Un punto importante es la capacidad de agregar sus propias reglas de búsqueda de vulnerabilidades a la herramienta; esto eliminará la primera razón por la que se pierde una vulnerabilidad.
Por lo tanto, si no encontró una vulnerabilidad existente en los resultados del análisis, primero debe averiguar el motivo de la omisión; por lo general, un proveedor puede ayudarlo. Si el motivo se encuentra en la base de reglas o en la configuración de escaneo, la situación puede eliminarse con bastante facilidad. Lo más importante es evaluar la profundidad del análisis, es decir, lo que, en principio, le permite buscar el motor.
Competencias
Después de leer el artículo en este lugar, podemos suponer que para trabajar con la herramienta, se necesita una gran experiencia del desarrollador, porque debe comprender qué respuestas son falsas y cuáles son verdaderas. En mi opinión, todo depende de qué tan amigable se comporte el instrumento. Si proporciona una funcionalidad conveniente y comprensible, descripciones comprensibles de vulnerabilidades con ejemplos, enlaces y recomendaciones en diferentes idiomas, si la herramienta muestra rastros de vulnerabilidades relacionadas con el análisis del flujo de datos, no necesitará tener una profunda experiencia del desarrollador con una comprensión de todas las sutilezas del lenguaje de programación y marcos. Sin embargo, debe haber un fondo mínimo en desarrollo para poder leer el código.
Integración en el proceso de desarrollo.
Al final del artículo, tocaremos brevemente uno de los temas más importantes del uso de la herramienta, y lo consideraremos en detalle en los siguientes artículos. Suponga que decide usar un analizador estático. Sin embargo, tiene un proceso de desarrollo establecido, tanto tecnológico como organizativo, y no desea cambiarlo (nadie lo dará).
La herramienta debe tener una interfaz no gráfica completa (por ejemplo, CLI o REST API), con la que puede integrar el analizador en cualquiera de sus procesos. Es bueno que el analizador tenga integraciones listas para usar con varios componentes: complementos para IDE o sistemas de compilación, integraciones con sistemas de control de versiones, complementos para servidores CI / CD (Jenkins, TeamCity), integración con sistemas de gestión de proyectos (JIRA) o trabajo con usuarios ( Directorio Activo).
La integración del análisis estático en el proceso de desarrollo (el denominado SDLC) es la forma más efectiva de usarlo si el proceso está bien establecido y todos los participantes están de acuerdo y saben por qué esto es necesario. El análisis constante del código después de los cambios o actualizaciones del analizador le permitirá encontrar vulnerabilidades lo antes posible. La separación de los roles de desarrolladores y especialistas en seguridad de la información, una indicación clara de los requisitos de seguridad de la información y la integración suave en el proceso actual (por ejemplo, al principio, la naturaleza de asesoramiento del sistema) le permitirá utilizar la herramienta sin dolor y de manera útil. Sin embargo, nadie ha cancelado el uso manual de la herramienta, si su modelo de desarrollo no implica un proceso similar.
Resumen
El artículo contiene recomendaciones básicas para comenzar a usar un analizador estático. Un buen analizador funciona en un orden de magnitud mejor que cualquier verificador ligero; busca problemas de una complejidad fundamentalmente diferente. Por lo tanto, es necesario tener en cuenta las características del análisis estático como tecnología, pero al mismo tiempo elegir una herramienta específica para que su funcionalidad suavice al máximo todas esas características.