Executando verificação de segurança...
5

Pitch: Construí um Scanner SCA em Go nas minhas férias

Olá pessoal! Este é meu primeiro post aqui no TabNews e pretendo começar a falar mais sobre segurança, AppSec e scanners em geral. Inicialmente gostaria de compartilhar minha experiencia construindo algo que curto muito, ferramentas CLI, scanners e SCA. Venho estudando muito Go e bastante appsec não apenas para o meu trabalho mas para contribuir com a comunidade visando aumentar a discussão sobre segurança, appsec e afins.

Atualmente estou de férias e há um tempo venho pensando em como os scanners de SCA (Software Composition Analysis) funcionam hoje. A lentidão nos scans e o ruído desnecessário com falsos positivos acabam atrapalhando muito a priorização dos times de segurança e dos programadores. Por consequência, a recomendação quase sempre é apenas "atualize o pacote", pois existe uma confiança cega no SCA devido ao baixo número de falsos positivos.

Porém, eles existem. Seja uma vulnerabilidade muito recente que ainda está sendo avaliada (mas os scanners já estão apitando), ou um pacote que não é mais utilizado pela aplicação, mas que continua listado no arquivo de manifesto.

Pensando em resolver não apenas essas dores, mas também o problema de usar múltiplas ferramentas (uma para scan no terminal, outra para gerar SBOM, etc.), optei por criar um novo scanner SCA focado em informação e dados. (contribuir para que se posso fazer o meu né? Mas acreditem estou estudando Go e pensei que poderia ser um bom case)

🎯 O objetivo do S.C.A.R.

Inicialmente, a ideia é te dar visibilidade clara e, futuramente, te ajudar a entender se um pacote é ou não efetivamente chamado pela aplicação. O foco é reduzir ruído, tempo de execução e ajudar os times a priorizarem com assertividade.

Somado a isso, temos o .scarignore. Ele consiste em um arquivo focado na mitigação de ruídos: você pode ignorar uma vulnerabilidade que já validou e que não está te afetando (seja pelo contexto da infra ou porque você decidiu assumir o risco temporariamente).

🛠️ Por que Go e OSV?

Go foi escolhido por ser excelente para ferramentas CLI, pela distribuição fácil de binário único e pela facilidade de trabalhar com a linguagem (bati a cabeça um pouco com defer e tipagem, mas de resto foi tudo certo).

O OSV Database é minha escolha de muito tempo. Sempre gostei de trabalhar com essa API: é extremamente simples e bem documentada. Isso facilita muito e permite fazer um bom trabalho do lado do scanner, como o uso de Batch Requests. O S.C.A.R. faz uma única requisição independente do número de pacotes. Além disso, implementei um cache local de 1 hora. Se durante esse período você fizer scans nos mesmos pacotes (muito comum em CI/CD), ele usa o cache primeiro e só bate na API se o pacote for novo (com a opção de ignorar o cache via flag, se necessário).

🧬 Dependências Diretas vs Transitivas

Uma feature que sempre gostei muito de ter é a visibilidade da relação entre dependências diretas e indiretas (dependências de dependências). A importância disso consiste em saber exatamente qual pacote está vulnerável: foi um pacote que o programador adicionou conscientemente ou é uma dependência filha? Saber de quem ela é filha é crucial para entender qual pacote raiz você precisa atualizar.

🧾 Compliance: SBOM e VEX

Existe, claro, o suporte a SBOM com VEX. É uma das coisas que sempre sinto falta para uma análise mais assertiva ou para importar em plataformas de gestão.

No S.C.A.R., as vulnerabilidades sinalizadas para serem ignoradas no .scarignore não são omitidas do relatório final. Elas são enviadas, porém com o status de not_affected no VEX, justamente para manter a visibilidade e a transparência. O SBOM é exportado no formato CycloneDX 1.4, um padrão globalmente aceito de fácil importação.

🧗 Os Desafios

Falando sobre os desafios de se construir algo assim, a principal dor de cabeça foi o ecossistema do Python. Lidar com requirements.txt, pyproject.toml, setup.py... meu deus. Além de muitas vezes os projetos terem mais de um arquivo (um requirements.txt somado a algum outro para a distribuição), precisei concatenar esses pacotes para serem analisados e unificá-los no relatório, independente de qual arquivo os declarou.

O ambiente JavaScript sofre do mesmo mal (yarn.lock vs package-lock.json), mas por terem um formato JSON nativo, facilitou bastante a extração.

🚀 Próximos Passos

Para o futuro, penso em:

Ampliar o suporte a mais ecossistemas (Java, PHP, Rust).

Incluir um mecanismo de análise de licenças. Muita gente usa software open-source sem saber como a licença funciona e como ela pode "contaminar" a aplicação, o que pode dar muita dor de cabeça jurídica depois.

É isso! O código está aberto no GitHub https://github.com/JAugusto42/scar e qualquer feedback é muito bem-vindo.

Carregando publicação patrocinada...