ASOC 'Faça Você Mesmo': Criando uma Alternativa ao DefectDojo com Dados do BDU FSTEC

ASOC 'Faça Você Mesmo': Criando uma Alternativa ao DefectDojo com Dados do BDU FSTEC

Explore como um desenvolvedor construiu uma plataforma de Gerenciamento de Vulnerabilidades (ASOC) personalizada usando Go, PostgreSQL e React, focando em alto desempenho e integração com fontes de dados russas como o BDU FSTEC.

MundiX News·13 de maio de 2026·15 min de leitura·👁 6 views

ASOC 'Faça Você Mesmo': Criando uma Alternativa ao DefectDojo com Dados do BDU FSTEC

Ao buscar soluções de código aberto para Gerenciamento de Vulnerabilidades (ASOC), o cenário pode ser desanimador, com o DefectDojo como a opção mais proeminente. No entanto, relatos de colegas sobre dificuldades de desempenho com grandes volumes de dados e a ausência de integração nativa com o Banco de Dados de Vulnerabilidades (BDU) do FSTEC (Serviço Federal de Controle Técnico e de Exportação da Rússia) levaram à criação de uma plataforma ASOC personalizada. Esta nova solução, construída com Go, PostgreSQL, Redis Streams e React, promete lidar com milhões de registros sem lentidão significativa, enriquecer dados de sete fontes distintas e aplicar uma fórmula de priorização que considera não apenas CVSS, mas também EPSS, CISA KEV e o BDU FSTEC. Este artigo detalha as decisões arquiteturais, os desafios encontrados e o motivo pelo qual a ORM foi descartada antes mesmo da primeira linha de SQL ser escrita.

Esta não é uma análise de um produto comercial pronto ou um comunicado de relações públicas. É uma exploração de como e por que a plataforma de código aberto Red Lycoris foi projetada para o armazenamento centralizado, deduplicação, enriquecimento e priorização de vulnerabilidades. Desenvolvida por um único indivíduo, a esperança é que ela possa ser útil para outros. Críticas construtivas sobre a arquitetura são bem-vindas e apreciadas.

O que é ASOC e por que ele é necessário?

ASOC (Application Security Orchestration and Correlation) atua como uma camada intermediária entre diversas ferramentas de segurança e os tomadores de decisão, como equipes de AppSec, desenvolvedores, líderes técnicos e gerentes de produto. Sua função principal é consolidar resultados de diferentes scanners em um único local, normalizar os dados, eliminar duplicatas, associar descobertas a projetos específicos e destacar o que realmente exige atenção.

À medida que o processo de AppSec em uma empresa evolui, é comum a adoção de múltiplos scanners especializados. Cada organização possui um conjunto de ferramentas único, que pode incluir soluções de código aberto, comerciais ou scripts customizados em pipelines de CI. As categorias de verificação, no entanto, frequentemente se repetem:

  • SAST (Static Application Security Testing): Análise estática de código (ex: Semgrep, SonarQube, CodeQL).
  • SCA (Software Composition Analysis): Análise de dependências e componentes de código aberto (ex: Trivy, Grype, Snyk).
  • DAST (Dynamic Application Security Testing): Testes dinâmicos de aplicações (ex: OWASP ZAP, Burp Suite).
  • IaC (Infrastructure as Code): Verificação de código de infraestrutura e configurações (ex: Checkov, tfsec).
  • Secrets Detection: Busca por segredos, tokens e chaves (ex: TruffleHog, Gitleaks).
  • Container Scanning: Análise de imagens e pacotes em contêineres (ex: Trivy image).

A complexidade surge não das ferramentas em si, mas da forma como elas se comunicam. Cada scanner possui seu próprio formato de relatório, modelo de criticidade e maneira de descrever uma vulnerabilidade. Uma mesma CVE, como a CVE-2021-44228, pode ser identificada por um scanner SCA em uma dependência, por um scanner de contêineres em uma imagem compilada, ou por outra ferramenta em um arquivo de lock. Formalmente, são múltiplas entradas, mas conceitualmente podem se referir a um único problema em um produto específico.

Multiplique isso por dezenas de serviços, várias equipes, diferentes ambientes e execuções regulares em CI/CD. O resultado é um fluxo de descobertas, onde algumas são duplicadas, outras desatualizadas, algumas sem impacto real, e as vulnerabilidades verdadeiramente críticas podem se perder no ruído. É aqui que o ASOC se torna essencial: não para substituir os scanners, mas para integrar seus resultados, normalizar os dados, correlacionar descobertas e auxiliar as equipes a priorizar as correções.

Um ASOC eficaz cumpre várias funções:

  • Importação e Parsing: Recebe relatórios de diversas ferramentas e os converte para um modelo de dados unificado.
  • Normalização: Padroniza nomes de campos, níveis de severidade, status, tipos de vulnerabilidade e metadados.
  • Deduplicação: Agrupa descobertas repetidas para evitar múltiplas entradas críticas para o mesmo problema.
  • Priorização: Ajuda a determinar a ordem de correção, reconhecendo que "50 descobertas críticas de um scanner" e a capacidade real de uma equipe de desenvolvimento são realidades distintas.
  • API e Interface: Fornece aos pipelines de CI/CD um meio claro de enviar resultados e oferece às equipes de AppSec e desenvolvedores uma interface amigável para análise, filtragem e tomada de decisões.

É importante distinguir ASOC de scanners, SIEM (Security Information and Event Management) ou ASM/ASMP (Attack Surface Management/Monitoring). O ASOC não realiza varreduras; ele processa os resultados de outras ferramentas. SIEM foca em eventos de segurança e logs, enquanto ASM/ASMP lida com a superfície de ataque externa. O ASOC, por outro lado, está focado no processo de AppSec dentro do ciclo de vida de desenvolvimento de software (SDLC), abrangendo código, dependências, contêineres, IaC, segredos e os resultados de verificações em CI/CD.

Por que não continuar com o DefectDojo?

O DefectDojo é o ASOC de código aberto mais conhecido. No entanto, após ouvir relatos de colegas e realizar uma análise preliminar, ficou claro que ele não atendia completamente às minhas necessidades. Os principais pontos de atenção foram:

  • Desempenho: Com aproximadamente 100.000 descobertas, a interface do DefectDojo já pode apresentar lentidão, com filtros demorados e uma resposta menos ágil. Com mais de 1 milhão de registros, a usabilidade se torna um desafio sem otimizações específicas. A combinação clássica de Django, ORM e paginação via OFFSET pode impactar negativamente o desempenho em tabelas grandes.
  • Integração com BDU FSTEC: Para usuários russos, o BDU FSTEC é uma fonte de dados crucial. Embora o DefectDojo geralmente inclua NVD, EPSS e KEV, a integração com o BDU requer desenvolvimento adicional, não sendo uma funcionalidade pronta.
  • Interface Desatualizada: Utilizando Bootstrap 3 e templates Django, a interface, embora funcional, não oferece o nível de experiência do usuário (UX) esperado em 2026 para uma ferramenta ASOC. Tabelas rápidas para grandes volumes, filtragem facetada robusta, persistência de estado na URL e a capacidade de compartilhar links com filtros aplicados são desejáveis.
  • Operação em Rede Fechada: Para setores como o bancário, governamental e de telecomunicações, a ausência de conexão com a internet é um requisito comum. O DefectDojo pode ser implantado offline, mas a limitação de fontes externas de enriquecimento o transforma mais em um repositório de descobertas do que em uma ferramenta de priorização.

Não há uma intenção de desmerecer o DefectDojo. Para muitas equipes, ele ainda representa uma escolha mais madura e segura, especialmente com volumes de dados moderados. No entanto, a prioridade neste projeto era focar em grandes volumes de dados, contexto russo, operação em rede fechada e uma interface otimizada para análise rápida de descobertas.

Requisitos da Nova Plataforma

Inicialmente, foram definidos os seguintes requisitos:

  • Implantação Local, Opcionalmente Offline: Atender a requisitos de segurança e conformidade de setores como bancos, governo e telecomunicações, onde soluções em nuvem podem não ser viáveis.
  • BDU FSTEC como Fonte Primária: Integrar o BDU FSTEC como uma fonte essencial para verificação, enriquecimento e priorização de vulnerabilidades no contexto russo.
  • Desempenho com 1 Milhão+ Registros: Garantir que a plataforma funcione sem lentidão, mesmo com centenas de milhares de descobertas acumuladas ao longo do tempo, especialmente com a integração em CI/CD.
  • Arquitetura Simples: Utilizar um único binário, PostgreSQL e Redis, evitando a complexidade de Kubernetes e infraestruturas extensas, permitindo a implantação em uma VM comum.
  • API REST Clara com OpenAPI: Facilitar a integração com CI/CD, scripts e automação, além de permitir importação manual.
  • Interface Moderna: Oferecer uma UI rápida, clara e visualmente agradável, sem sobrecarga, fugindo do visual de um painel administrativo de 2012.
  • Idioma Português como Padrão: Garantir que a interface, os status e as descrições sejam compreensíveis para equipes brasileiras sem a necessidade de alternância constante de contexto.

O nome "Red Lycoris" surgiu de forma orgânica, sem uma estratégia de marca elaborada, inspirado pela frequência com que a flor aparecia em animes.

Stack Tecnológico e Justificativas

A escolha do stack tecnológico foi guiada por restrições específicas: operação em rede fechada, grandes volumes de dados, facilidade de implantação e suporte previsível.

  • Backend: Go 1.25 com chi router. Escolhido por gerar um único binário estático, rápido tempo de inicialização, boa concorrência e um modelo conveniente para processamento em background.
  • Banco de Dados: PostgreSQL 16. Utilizado para armazenar dados de enriquecimento em JSONB, criar visualizações materializadas para grandes volumes de dados, implementar índices parciais para consultas frequentes e particionamento para o log de auditoria.
  • Fila de Mensagens: Redis 7 Streams. Essencial para tarefas em background, oferecendo uma fila confiável com grupos de consumidores. Kafka seria excessivo para uma implantação em um único nó.
  • Frontend: React 18 com TypeScript strict e Vite. Bibliotecas como TanStack Table, Query e Virtual foram escolhidas para lidar com as complexidades de tabelas de alto desempenho, cache, filtros e virtualização.
  • Estilização: Tailwind CSS com shadcn/ui. Permite a criação rápida de interfaces limpas sem a necessidade de gerenciar um grande volume de CSS customizado. O tema escuro é o padrão.
  • Acesso ao Banco de Dados: pgx/v5, sem ORM. Essencial para controle total sobre SQL, índices, planos de consulta e comportamento em tabelas grandes.
  • Migrações: golang-migrate. Para gerenciar migrações SQL de forma simples e direta.
  • Implantação: Docker Compose. Evita a dependência obrigatória de Kubernetes, permitindo a implantação da plataforma com um único comando docker compose up -d em uma VM comum.

Decisões arquiteturais importantes foram documentadas no arquivo CLAUDE.md do repositório, ajudando a manter o foco e evitar a introdução desnecessária de novas tecnologias. Essas decisões incluem:

  • Sem ORM, apenas SQL puro via pgx/v5.
  • Paginação via cursor, não OFFSET.
  • Novas dependências apenas com justificativa explícita.
  • Sem abstrações "para o futuro"; interfaces são criadas apenas quando há pelo menos duas implementações.

A decisão de abandonar a ORM, embora controversa para alguns, foi uma escolha técnica consciente neste projeto, focada em controle e desempenho.

Arquitetura: Fluxo de Dados e Processamento

A arquitetura foi projetada para ser eficiente e escalável. A imagem ilustrativa, gerada por IA, representa o fluxo de dados.

Parsers: Autodetecção em vez de Seleção Manual

Diferente do DefectDojo, onde o tipo de scanner precisa ser especificado manualmente durante a importação, a Red Lycoris tenta detectar o formato do arquivo automaticamente. Atualmente, a plataforma inclui 10 parsers integrados para formatos como SARIF, Trivy JSON, Grype JSON, Semgrep JSON, Gosec JSON/SARIF, ZAP JSON, TruffleHog NDJSON/array, Gitleaks JSON, Checkov JSON e um parser genérico.

A autodetecção é implementada de forma simples: cada parser implementa um método CanParse([]byte) bool que verifica características específicas do formato. Por exemplo, para SARIF, a função verifica os campos $schema e version. Os parsers são testados em sequência, e o primeiro a identificar o formato é responsável por processar o arquivo. O GenericParser atua como um fallback para JSONs simples com um conjunto mínimo de campos, útil para ferramentas internas ou customizadas.

A interface de upload é direta, permitindo o envio de resultados via UI.

Deduplicação: O Desafio da Identificação de Duplicatas

A deduplicação é uma das tarefas mais complexas em ASOC. A ideia é simples: se uma descoberta já existe, não criar uma nova. Na prática, a questão é: o que define uma duplicata? Existem várias abordagens, cada uma com suas desvantagens:

  • CVE + Componente: Adequado para SCA, mas ineficaz para SAST sem CVE.
  • Caminho do Arquivo + Linha: Útil para código, mas problemático para SCA, onde um único pom.xml pode gerar múltiplos CVEs.
  • ID da Regra + Arquivo: Agrupa diferentes ocorrências da mesma regra em um arquivo.
  • Hash Completo da Descoberta: Raramente agrupa algo, pois a alteração de um único campo invalida o hash.

A solução adotada é um híbrido: um "fingerprint" é calculado a partir de campos estáveis que descrevem a natureza da descoberta, e o resultado é processado via SHA256. O cálculo do fingerprint considera campos como tipo de descoberta (Kind), ID da regra, ID do CVE, caminho do arquivo, linha inicial e final, ID do CWE, componente e versão.

Um detalhe crucial é a inclusão do Kind (tipo de descoberta) no fingerprint. Isso garante que descobertas SCA e SAST não sejam agrupadas como uma única entrada, mesmo que compartilhem um CVE, pois representam classes de problemas distintas que devem ser vistas separadamente.

Em caso de importação repetida, se um fingerprint já existir no banco de dados, a nova descoberta não é criada. Em vez disso, os campos da entrada existente são atualizados: last_seen é definido como o momento atual, e times_seen é incrementado. Isso indica que o problema ainda é relevante sem poluir a interface com entradas idênticas.

Um histórico de eventos é mantido na tabela finding_events, registrando mudanças de status, atribuições e comentários, o que é vital para auditoria e para responder a perguntas sobre quem e por que uma vulnerabilidade foi fechada.

Para segredos, uma lógica de fingerprint separada é utilizada. Como o valor do segredo não pode ser armazenado em texto plano no banco de dados, o fingerprint inclui apenas um hash dos atributos estáveis, e o segredo em si não é persistido.

Enriquecimento: 7 Fontes, 3 Workers, Redis Streams

Um CVE isolado, sem contexto, tem pouco valor. Informações adicionais como EPSS, KEV, BDU FSTEC, CWE, links de referência e uma estimativa de perigo real transformam uma simples entrada em uma base para priorização. A Red Lycoris utiliza sete fontes de enriquecimento:

  • NVD API 2.0: CVSS v2/v3.1/v4.0, descrições, CPE matches, links (atualização a cada 2 horas).
  • EPSS / FIRST: Probabilidade de exploração nos próximos 30 dias (atualização diária).
  • CISA KEV: Vulnerabilidades ativamente exploradas (atualização a cada 6 horas).
  • BDU FSTEC: Catálogo russo de vulnerabilidades, links com CVE e CWE (atualização semanal).
  • OSV: Vulnerabilidades em ecossistemas de código aberto (atualização diária).
  • CWE / MITRE: Classificação de tipos de fraquezas (atualização mensal).
  • NVD CPE: Dicionário de produtos e plataformas (atualização semanal).

Todos os catálogos são espelhados localmente. Isso é crucial para ambientes de rede fechada, garantindo que a plataforma continue funcionando com os dados mais recentes mesmo sem acesso à internet.

Tecnicamente, o enriquecimento é implementado usando Redis Streams e um grupo de três workers. Cada mensagem na fila contém um finding_id. Um worker recupera a descoberta do banco de dados, consulta os catálogos locais, adiciona os dados encontrados aos campos JSONB e recalcula o priority_score. O Redis Streams foi escolhido por sua simplicidade e adequação ao cenário, evitando a complexidade de Kafka para uma implantação em VM única.

A confirmação via XACK só ocorre após o processamento bem-sucedido. Se um worker falhar, a mensagem permanece não confirmada e pode ser processada por outro worker. O processamento repetido é seguro devido à idempotência garantida no nível do banco de dados com INSERT ... ON CONFLICT DO UPDATE.

Priorização: Uma Fórmula, Não Apenas "Crítico"

Com dezenas de milhares de descobertas marcadas como "críticas", o nível de severidade por si só se torna insuficiente. É necessária uma avaliação que considere o contexto real: a vulnerabilidade está sendo explorada? Está no KEV? Qual a probabilidade de exploração (EPSS)? O serviço afetado é exposto externamente? Existe uma correção disponível?

A Red Lycoris calcula um priority_score usando uma fórmula que pondera diversos fatores:

priority_score = cvss_base × 0.30 + epss × 100 × 0.25 + (kev_bonus + urgency_bonus) × 0.20 + bdu_bonus × 0.10 + recency × 0.10 + exposure × 0.05 + trend_bonus × 0.05 + fix_bonus × 0.03

Onde:

  • cvss_base: O maior CVSS disponível (v4.0 > v3.1 > v2.0).
  • epss × 100: Probabilidade de exploração nos próximos 30 dias, normalizada para a escala 0-100.
  • kev_bonus: Bônus por estar no CISA KEV, com consideração especial para links com ransomware.
  • urgency_bonus: Contribuição maior quanto mais próximo o prazo do KEV.
  • bdu_bonus: Peso adicional se a vulnerabilidade estiver no BDU FSTEC.
  • recency: Frescor da vulnerabilidade com decaimento exponencial.
  • exposure: Coeficiente de acessibilidade do serviço (internet, rede interna, ambiente isolado).
  • trend_bonus: Aumento do EPSS na última semana.
  • fix_bonus: Disponibilidade de informações sobre correção (ex: em OSV).

O valor bruto é normalizado para o intervalo 0-10. A intenção é que o CVSS seja apenas um componente da avaliação, não a única fonte de verdade. Uma CVE com CVSS 9.8, mas com EPSS baixo, sem KEV e sem sinais de exploração, pode não ser a prioridade máxima. Em contrapartida, uma vulnerabilidade "Média" que já está no KEV com um prazo iminente deve ter prioridade elevada.

Para evitar cálculos pesados a cada abertura de lista, o priority_score final é armazenado e recalculado durante o enriquecimento e periodicamente por um processo em background. Isso cria uma "vitrine" otimizada para a interface, permitindo que os usuários vejam imediatamente a ordem de prioridade das correções.

Desempenho: Lições Aprendidas

O desempenho é um dos aspectos mais críticos e gratificantes deste projeto.

Paginação por Cursor em vez de OFFSET

A paginação clássica com OFFSET (SELECT * FROM findings WHERE ... LIMIT 50 OFFSET 50000;) torna-se lenta em tabelas grandes, pois o PostgreSQL precisa processar todas as linhas anteriores. A Red Lycoris utiliza paginação por cursor (keyset pagination): SELECT * FROM findings WHERE ... AND (first_seen, id) < ($cursor_first_seen, $cursor_id) ORDER BY first_seen DESC, id DESC LIMIT 51;. O cursor é um JSON base64-codificado contendo first_seen e id. Um índice composto (idx_findings_project_first_seen_id) é necessário para otimizar essa consulta. Essa abordagem mantém a velocidade de navegação independente do número da página, pois a base de dados apenas busca as próximas 50 linhas a partir do índice.

A desvantagem é a impossibilidade de saltar diretamente para uma página específica. No entanto, para um ASOC, onde o foco é filtrar, ordenar e buscar descobertas específicas, essa limitação é aceitável.

pgx/v5 e SQL Puro, Sem ORM

O uso de pgx/v5 sem ORM é uma decisão que gera debates. ORMs são convenientes para operações simples, mas em consultas complexas com filtros, JOINs e agregações, eles podem se tornar um obstáculo. Com pgx/v5, o SQL escrito é exatamente o que é executado no banco de dados, facilitando a compreensão, otimização e depuração. A alteração de esquema é uma migração SQL explícita, não um efeito colateral da modificação de um modelo.

Índices Focados em Consultas Específicas

Os índices foram adicionados com critério, focando em cenários de interface e API específicos, em vez de indexar tudo indiscriminadamente. Índices parciais são particularmente úteis para consultas direcionadas a subconjuntos de dados (ex: descobertas com CVEs ou com correções disponíveis).

A conclusão principal é que o desempenho foi alcançado através de um conjunto de decisões técnicas consistentes: paginação por cursor, SQL claro, índices adequados e a ausência de abstrações desnecessárias em caminhos críticos.

Segurança da Plataforma

Como parte do processo de segurança, a própria plataforma ASOC deve ser segura. Ela armazena dados sensíveis, como resultados de varreduras, segredos em relatórios, histórico de vulnerabilidades e ações de usuários.

  • Autenticação: A interface utiliza sessões baseadas em cookies (HttpOnly, Secure, SameSite=Strict) para mitigar XSS e CSRF. Para CI/CD, são usados Bearer tokens vinculados a projetos específicos, com opção de expiração e rotação. O administrador inicial é criado via variáveis de ambiente (BOOTSTRAP_ADMIN_EMAIL, BOOTSTRAP_ADMIN_PASSWORD), com a exigência de alteração de senha após o primeiro login.
🛡️⚡

Pare de pesquisar. Comece a hackear.

O MundiX é seu copiloto de pentest com IA: comandos exatos, análise de outputs e próximo passo na kill chain — em segundos.

Testar grátis por 7 dias →

Sem cartão para começar · Planos a partir de R$49/mês

📤 Compartilhar & Baixar

📩 Newsletter MundiX

Receba novidades de cibersegurança + um checklist de pentest grátis. Sem spam.

Ao assinar você concorda em receber e-mails. Cancele quando quiser.