Como usar a análise estática corretamente

Agora, mais e mais pessoas estão falando sobre análise estática para procurar vulnerabilidades como um estágio necessário do desenvolvimento. No entanto, muitos falam sobre os problemas da análise estática. Conversamos muito sobre isso no passado do Positive Hack Days e, com base nos resultados dessas discussões, já escrevemos sobre como o analisador estático funciona. Se você experimentou alguma ferramenta séria, pode se assustar com longos relatórios com recomendações confusas, dificuldades na configuração da ferramenta e falsos positivos. Então, a análise estática ainda é necessária?

Nossa experiência sugere o que é necessário. E muitos dos problemas que surgem quando você olha a ferramenta pela primeira vez, é bem possível resolver. Vou tentar lhe dizer o que o usuário pode fazer e como deve ser o analisador, para que seu uso seja útil e não introduza "outra ferramenta desnecessária exigida pela equipe de segurança".


Sobre a análise estática


Então, já falamos sobre as limitações teóricas da análise estática. Por exemplo, a análise estática profunda tenta resolver problemas que são exponenciais em complexidade. Portanto, cada ferramenta busca um compromisso entre o tempo gasto, os recursos gastos, o número de vulnerabilidades encontradas e o número de falsos positivos.

Por que precisamos de uma análise aprofundada? Qualquer IDE encontra rapidamente erros, às vezes até relacionados à segurança - o que geralmente é um problema exponencial? Um exemplo clássico é a injeção de SQL (e qualquer outra injeção, como XSS, RCE e similares), que passa por várias funções (ou seja, a leitura de dados do usuário e a execução da consulta ocorrem em diferentes funções). Sua pesquisa requer análise interprocedural do fluxo de dados, e essa é uma tarefa de complexidade exponencial. Concordo, sem procurar essas vulnerabilidades, a análise não pode ser considerada profunda. Pelo mesmo motivo, você precisa analisar o código na íntegra, e não em partes - caso contrário, as vulnerabilidades interprocedenciais poderão ser perdidas.

Nos últimos anos, adquiri muita experiência na comunicação com clientes (potenciais) de vários analisadores estáticos. Em particular, discutimos reivindicações para as ferramentas com base nos resultados do primeiro uso (piloto). A maioria das reivindicações segue de uma maneira ou de outra as limitações teóricas da tecnologia. Além disso, as ferramentas podem simplesmente não ter a funcionalidade que o usuário precisa. No entanto, na minha opinião, os analisadores podem se mover (e estão se movendo) em direção ao usuário em termos de solução dos problemas indicados abaixo. Mas você também precisa poder usar analisadores, nivelando as conseqüências dos mesmos problemas - como se vê, isso não é tão difícil. Vamos em ordem.

Você pode imaginar uma situação de modelo: você decide tentar a tecnologia em ação ou escolhe um analisador estático - passe um piloto. Obviamente, você não confia nos casos de teste do fornecedor e deseja tentar analisar seu código (ao mesmo tempo, pode encontrar vulnerabilidades reais e corrigi-las). Você recebe um instalador ou uma máquina virtual finalizada com um sistema por um curto período de tempo.

Executar análise


Primeiro você precisa executar a análise. Você acessa a interface e tudo parece claro: faça o upload do arquivo com o código-fonte no formulário e clique em "analisar". Mas não: você recebe vários formulários com campos diferentes que precisam ser preenchidos de alguma forma. É necessário especificar linguagens de programação, algumas configurações do analisador, selecionar pacotes de vulnerabilidades (como você sabe o que está incluído neles?) E assim por diante. Você passa neste teste e a análise começa. Ah, não - um erro de verificação. “O formato não atende aos requisitos”, “Um conjunto de códigos é necessário para este idioma”, “Arquivos para verificação não foram encontrados” ... Se você não escreveu esse código, ainda precisará procurar ajuda dos desenvolvedores.


Desenvolvedor entrega o código fonte para teste

Atenção especial é dada aos requisitos para o código de construção. A maioria dos analisadores de várias linguagens exige que o código seja coletado durante a análise (linguagens da JVM - Java, Scala, Kotlin e similares, C / C ++, Objective-C, C #). Você entende como é doloroso: reproduzir o ambiente de um grande projeto para montagem em uma nova máquina. Por outro lado, esses requisitos são justificados, pois seguem a tecnologia de análise e as especificidades dessas linguagens.

Como os analisadores resolvem esses problemas? Em primeiro lugar, eles tornam o lançamento da análise o mais automatizado possível. Idealmente, basta baixar um arquivo de qualquer formato, e o analisador deve entender quais idiomas existem, como tentar criar e como definir o restante das configurações por padrão, para que os resultados sejam os mais completos possíveis. É claro que é impossível prever tudo - no entanto, você pode tentar lidar com a maioria dos casos.

Os requisitos de montagem precisam ser feitos o mais macio possível. Por exemplo, para linguagens da JVM, você não precisa exigir montagem durante a análise - basta pedir para carregar artefatos, ou seja, o código montado junto com as fontes (o que é muito mais simples). Para o Xcode, no caso do Objective-C, a montagem pode ser automatizada na maioria dos casos. Se não foi possível coletar o código, o analisador pode tentar realizar uma análise parcial. Seus resultados não serão tão completos, mas é melhor do que nenhum resultado. Também é conveniente se o módulo de análise puder ser colocado na máquina para o desenvolvedor, onde o conjunto de códigos já está configurado, enquanto a arquitetura deve permitir que os outros módulos e a parte da interface sejam transferidos para outra máquina.

Por fim, o analisador deve apresentar os requisitos de formato mais suave e lidar com os próprios arquivos de entrada. Um arquivo com código-fonte, arquivos aninhados, um arquivo de um repositório, um link para um repositório, um arquivo de um produto, um arquivo executável de um produto - é bom se o analisador suportar tudo isso.

No entanto, não esqueça que o analisador não possui inteligência artificial e não pode prever tudo. Portanto, se ocorrerem erros, você deve se familiarizar com o manual - há muitas coisas úteis na preparação do código para análise. Bem, todo esse trabalho de lançamento de uma varredura durante a implementação do analisador é feito apenas uma vez para cada base de código. Na maioria das vezes, o analisador geralmente é integrado ao ciclo do IC, ou seja, não haverá problemas com a montagem.

Processo de análise


Ok, a verificação foi iniciada. Uma hora passa - sem resultados. A barra de progresso trava em algum lugar no meio, não está claro com qual porcentagem e qual previsão é concluída. A segunda hora passa - o progresso avançou 99% e está suspenso por meia hora. A terceira hora passa e o analisador falha, relatando uma falta de RAM. Ou trava mais uma hora e termina. Você poderia esperar que a análise passasse na mesma velocidade do seu estilo de verificação, e aqui as expectativas divergirão bastante da realidade.


Sim, um bom analisador estático pode consumir muitos recursos, apontei um dos motivos acima: encontrar vulnerabilidades complexas é uma tarefa exponencialmente difícil. Portanto, quanto mais recursos houver e mais tempo, melhores serão os resultados (com um bom mecanismo, é claro). É realmente difícil prever o tempo de análise e os recursos necessários - o tempo de operação dos algoritmos de análise estática depende fortemente de construções de linguagem, da complexidade do código, da profundidade das chamadas - características difíceis de calcular antecipadamente.

O problema com os recursos é um mal necessário. Você precisa ter cuidado com a alocação dos recursos necessários, aguardar pacientemente a conclusão da verificação e também entender que ninguém pode prever com precisão os recursos necessários para o analisador, mesmo com uma determinada base de código, e você deve estar preparado para alterar esses parâmetros. Além disso, os parâmetros necessários podem mudar mesmo sem a atualização da base de código - devido à atualização do analisador.

No entanto, o analisador pode ajudar um pouco com esse problema. É capaz de separar a parte que exige muitos recursos (mecanismos) e a interface em máquinas diferentes. Isso permitirá que você não carregue máquinas com programas desnecessários que diminuirão o trabalho deles, enquanto será possível usar a interface do sistema para qualquer carga de trabalho nas varreduras (por exemplo, para exibir e editar resultados). Isso também facilitará o dimensionamento sem a reinstalação de todo o sistema (elevamos o analisador em uma nova máquina virtual, especificamos o IP da máquina principal - e pronto).

Além disso, o analisador pode permitir que você escolha a profundidade da análise, desabilite as verificações pesadas, use análises incrementais (nas quais nem todo o código é verificado, mas apenas alterado). Essas coisas devem ser usadas com muito cuidado, pois podem afetar bastante os resultados da verificação. Se você usar essa funcionalidade, é recomendável realizar uma análise completa em alguns intervalos.

Resultados da análise


Vamos passar para os resultados da verificação (por um longo tempo, fomos até eles). Você aguarda o número de vulnerabilidades na janela do analisador com apreensão e fica muito surpreso ao vê-lo. 156 crítico, 1260 médio e 3210 baixo. Você vai para a página de resultados e se afoga no número de problemas encontrados. Você baixa um relatório em pdf e vê vários milhares de páginas de texto. Adivinha o que o desenvolvedor de código dirá quando vir uma tela dessas?


O guarda de segurança está carregando um relatório de vulnerabilidade para o desenvolvedor

Mas ainda vamos tentar ver os resultados, dar uma chance a ele. Depois de examinar cuidadosamente dezenas de ocorrências, você começa a entender por que existem tantas vulnerabilidades. Várias vulnerabilidades realmente parecem sérias, você entende que elas precisam ser corrigidas. No entanto, imediatamente você encontra cerca de uma dúzia de falsos. E também - um grande número de vulnerabilidades no código das bibliotecas. Você não corrigirá bibliotecas! E então você entende quanto tempo você gasta analisando os resultados. E esse procedimento deve ser repetido todos os dias, semanas, bem ou pelo menos a cada release. (Na verdade não).

Para começar, os falsos positivos podem ser entendidos de maneiras muito diferentes. Alguém não considerará falsas apenas vulnerabilidades críticas que podem ser exploradas no momento. Alguém considerará falsos apenas erros explícitos do analisador. Depende muito do que você deseja da ferramenta. Recomendamos que você considere quase todas as ocorrências, pois mesmo uma vulnerabilidade de baixo nível que não pode ser explorada no momento pode se transformar em um problema sério amanhã, por exemplo, devido a alterações no código e nas condições externas.

Ok, você precisa examinar todas as entradas, mas isso ainda é uma quantidade enorme de trabalho. E aqui os analisadores podem ajudar muito bem. A função mais importante do analisador é a capacidade de rastrear vulnerabilidades entre varreduras de um projeto, mantendo-o resistente a pequenas alterações que são padrão no desenvolvimento de código. Isso elimina o problema de que uma longa análise de vulnerabilidades precisa ser repetida: na primeira vez em que você gasta mais tempo, removendo falsos positivos e alterando a criticidade das ocorrências, mas você só precisa examinar novas vulnerabilidades, que serão várias vezes menores.

Bom, mas é necessário revisar todas as vulnerabilidades pela primeira vez? Recomendamos fazer isso, mas de um modo geral, isso não é necessário. Primeiro, os analisadores permitem filtrar os resultados por diretórios e arquivos: por exemplo, quando você inicia uma varredura, é possível excluir imediatamente quaisquer componentes, bibliotecas e códigos de teste da análise. Isso afetará a velocidade da análise. Em segundo lugar, os analisadores permitem filtrar os resultados por vulnerabilidades, ou seja, quando você inicia a verificação, você pode limitar o conjunto de vulnerabilidades. Finalmente, além da criticidade, o analisador pode produzir algo como a probabilidade de uma falsa vulnerabilidade (ou seja, sua confiança nessa vulnerabilidade). Usando essa métrica, você pode filtrar os resultados.

Separadamente, vale a pena notar a tecnologia de Análise de Composição de Software (agora está começando a ser suportada por um número crescente de instrumentos em diferentes níveis). A tecnologia permite detectar o uso de bibliotecas no seu código, determinar os nomes e versões, mostrar vulnerabilidades conhecidas e licenças. Essa tecnologia pode separar o código da biblioteca do seu, o que também pode filtrar os resultados.

Acontece que você pode lidar com o problema de abundantes resultados de análises, e isso não é muito difícil. E, embora a primeira visualização dos resultados possa levar algum tempo, quando você a digitaliza, ela será gasta cada vez menos. No entanto, observe novamente que você deve ter cuidado com qualquer filtragem de resultados - pode ignorar a vulnerabilidade. Mesmo que a biblioteca seja conhecida, isso não significa que não há vulnerabilidade nela. Se agora essa vulnerabilidade for detectada de maneira inadequada (ou seja, a ferramenta mostra muitos falsos positivos para essa vulnerabilidade) e você a desativa, ao atualizar o analisador, você pode pular a vulnerabilidade real.

Verifique o analisador


Entendido com um grande relatório e falsos positivos. Mas você quer ir além - para garantir que o analisador encontre as vulnerabilidades das quais você sabe com certeza (você pode ter intencionalmente descoberto ou encontrado outra ferramenta).


Para começar, é importante entender que o analisador não conseguiu encontrar a vulnerabilidade por vários motivos. O mais simples é que a verificação foi configurada incorretamente (você precisa prestar atenção às mensagens de erro). Mas, do ponto de vista da tecnologia de análise, os motivos podem ser diferentes. Um analisador estático consiste em dois componentes importantes: um mecanismo (contém toda a complexidade algorítmica e matemática) e uma base de regras de pesquisa de vulnerabilidades. Uma situação é quando o mecanismo permite encontrar uma vulnerabilidade dessa classe, mas não há vulnerabilidade na base de regras. Nesse caso, adicionar uma regra geralmente não é difícil. Uma situação completamente diferente, se o mecanismo, em princípio, não suportar tais vulnerabilidades - aqui a revisão pode ser muito significativa. Dei um exemplo no começo do artigo: a injeção de SQL nunca pode ser encontrada sem os algoritmos de análise de fluxo de dados.

Um analisador estático deve implementar um conjunto de algoritmos no mecanismo que cubra as classes disponíveis de vulnerabilidades para uma determinada linguagem de programação (análise do fluxo de controle, fluxo de dados, análise de intervalo etc.). Um ponto importante é a capacidade de adicionar suas próprias regras de pesquisa de vulnerabilidades à ferramenta - isso eliminará o primeiro motivo para a falta de uma vulnerabilidade.

Portanto, se você não encontrou uma vulnerabilidade existente nos resultados da verificação, primeiro você precisa descobrir o motivo da falha - geralmente um fornecedor pode ajudar com isso. Se o motivo estiver na base de regras ou na configuração da varredura, a situação poderá ser facilmente eliminada. O mais importante é avaliar a profundidade da análise, ou seja, o que, em princípio, permite pesquisar o mecanismo.

Competências


Depois de ler o artigo neste local, podemos assumir que, para trabalhar com a ferramenta, é necessária uma profunda experiência do desenvolvedor, pois você precisa entender quais respostas são falsas e quais são verdadeiras. Na minha opinião, tudo depende de quão amigável o instrumento se comporta. Se ele fornece funcionalidade conveniente e compreensível, descrições compreensíveis de vulnerabilidades com exemplos, links e recomendações em diferentes idiomas, se a ferramenta mostrar rastreamentos para vulnerabilidades relacionadas à análise do fluxo de dados, você não precisará ter um profundo conhecimento do desenvolvedor com uma compreensão de todas as sutilezas da linguagem de programação e estruturas. No entanto, deve haver um conhecimento mínimo em desenvolvimento para ler o código.

Integração no processo de desenvolvimento



No final do artigo, abordaremos brevemente uma das questões mais importantes do uso da ferramenta e a consideraremos em detalhes nos artigos a seguir. Suponha que você decida usar um analisador estático. No entanto, você possui um processo de desenvolvimento estabelecido, tanto tecnológico quanto organizacional, e não deseja alterá-lo (ninguém o dará).

A ferramenta deve ter uma interface não gráfica completa (por exemplo, CLI ou API REST), com a qual você pode integrar o analisador a qualquer um dos seus processos. É bom que o analisador tenha integrações prontas com vários componentes: plug-ins para IDEs ou sistemas de construção, integrações com sistemas de controle de versão, plug-ins para servidores de CI / CD (Jenkins, TeamCity), integração com sistemas de gerenciamento de projetos (JIRA) ou trabalho com usuários ( Active Directory).

A integração da análise estática no processo de desenvolvimento (o chamado SDLC) é a maneira mais eficaz de usá-la se o processo estiver bem estabelecido e todos os participantes concordarem e souberem por que isso é necessário. A análise constante do código após alterações ou atualizações no analisador permitirá encontrar vulnerabilidades o mais cedo possível. A separação dos papéis de desenvolvedores e especialistas em segurança da informação, uma indicação clara dos requisitos de segurança da informação e integração suave no processo atual (por exemplo, a princípio - a natureza consultiva do sistema) permitirá que você use a ferramenta sem dor e utilidade. No entanto, ninguém cancelou o uso manual da ferramenta, se o seu modelo de desenvolvimento não implicar um processo semelhante.

Sumário


O artigo contém recomendações básicas para começar a usar um analisador estático. Um bom analisador trabalha em uma ordem de magnitude melhor do que qualquer verificador leve; procura problemas de complexidade fundamentalmente diferente. Portanto, é necessário considerar os recursos da análise estática como uma tecnologia, mas ao mesmo tempo escolher uma ferramenta específica para que sua funcionalidade suavize ao máximo todos esses recursos.

Source: https://habr.com/ru/post/pt424255/


All Articles