DevOps Admin

Boas Práticas de SAST e DAST em Pipelines: Trivy, Snyk, SonarQube e OWASP ZAP para Times Ágeis Já leu

SAST e DAST: Fundamentos e Diferenças A segurança de aplicações é um dos pilares mais críticos do desenvolvimento moderno. Existem duas abordagens fundamentais para identificar vulnerabilidades: SAST (Static Application Security Testing) e DAST (Dynamic Application Security Testing). Compreender a diferença entre elas é essencial para construir uma estratégia de segurança eficaz em seus pipelines de CI/CD. SAST analisa o código-fonte, bytecode ou binários sem executar a aplicação. É como revisar um livro antes de publicá-lo, procurando por erros estruturais. DAST, por outro lado, testa a aplicação em execução, simulando ataques reais contra a aplicação rodando. É como testar um carro em uma pista, verificando como ele se comporta sob pressão. Ambas são complementares: SAST encontra problemas cedo no desenvolvimento, enquanto DAST identifica vulnerabilidades que só aparecem em tempo de execução ou em contextos específicos de produção. A integração de ambas em pipelines de CI/CD cria uma camada dupla de proteção. Você consegue bloquear código vulnerável antes mesmo de fazer deploy,

SAST e DAST: Fundamentos e Diferenças

A segurança de aplicações é um dos pilares mais críticos do desenvolvimento moderno. Existem duas abordagens fundamentais para identificar vulnerabilidades: SAST (Static Application Security Testing) e DAST (Dynamic Application Security Testing). Compreender a diferença entre elas é essencial para construir uma estratégia de segurança eficaz em seus pipelines de CI/CD.

SAST analisa o código-fonte, bytecode ou binários sem executar a aplicação. É como revisar um livro antes de publicá-lo, procurando por erros estruturais. DAST, por outro lado, testa a aplicação em execução, simulando ataques reais contra a aplicação rodando. É como testar um carro em uma pista, verificando como ele se comporta sob pressão. Ambas são complementares: SAST encontra problemas cedo no desenvolvimento, enquanto DAST identifica vulnerabilidades que só aparecem em tempo de execução ou em contextos específicos de produção.

A integração de ambas em pipelines de CI/CD cria uma camada dupla de proteção. Você consegue bloquear código vulnerável antes mesmo de fazer deploy, e também valida a segurança da aplicação já rodando. Neste artigo, vamos explorar as ferramentas mais populares e como integrá-las adequadamente.

Trivy: SAST Leve e Focado em Containers

O Trivy é uma ferramenta SAST desenvolvida pela Aqua Security que se destacou por sua leveza e velocidade. Ela foi projetada originalmente para varrer imagens de container, mas evoluiu para detectar vulnerabilidades em código-fonte, dependências e configurações. A grande vantagem do Trivy é a simplicidade: ele funciona com um único comando e integra perfeitamente em qualquer pipeline.

O Trivy mantém um banco de dados local de vulnerabilidades conhecidas (CVEs) que é atualizado automaticamente. Ele consegue identificar problemas em dependências do Python, Node.js, Go, Java e muitas outras linguagens. Para começar, basta instalar e executar:

# Instalação no Ubuntu/Debian
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | tee -a /etc/apt/sources.list.d/trivy.list
apt-get update && apt-get install trivy

# Escanear um repositório local
trivy fs --severity HIGH,CRITICAL ./seu-projeto

# Escanear uma imagem Docker
trivy image nginx:latest

# Gerar relatório em JSON para integração
trivy fs --format json --output results.json ./seu-projeto

A integração em um pipeline GitLab CI/CD é direta:

# .gitlab-ci.yml
stages:
  - security

trivy-scan:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy fs --severity HIGH,CRITICAL --exit-code 1 .
  artifacts:
    reports:
      sast: trivy-results.json
    when: always

O --exit-code 1 força a falha do job se vulnerabilidades críticas ou altas forem encontradas. Isso impede que código vulnerável chegue ao repositório principal. Você pode ajustar o nível de severidade conforme sua política de segurança. O Trivy também suporta análise de secrets (senhas expostas), o que é particularmente útil para evitar credenciais no repositório.

SonarQube: SAST Profundo com Qualidade de Código

O SonarQube é uma plataforma enterprise de análise de código que vai além de segurança. Ele combina SAST com análise de qualidade de código, identificando bugs, code smells, duplicações e vulnerabilidades. É especialmente poderoso para projetos grandes onde você precisa manter controle sobre múltiplos aspectos da qualidade.

SonarQube funciona em modo cliente-servidor. Você executa um scanner que envia os resultados para um servidor central, que processa e exibe os dados em um dashboard. A cobertura de linguagens é impressionante: Java, Python, JavaScript, C#, C++, Go, PHP, Swift, Kotlin e muitas outras. Para vulnerabilidades de segurança, o SonarQube usa regras que cobrem o OWASP Top 10 e CWE (Common Weakness Enumeration).

Configurar o SonarQube envolve dois passos: instalar o servidor e configurar o scanner em seu pipeline. Para começar com Docker:

# Iniciar servidor SonarQube (versão community)
docker run -d --name sonarqube \
  -p 9000:9000 \
  sonarqube:latest

# Acessar em http://localhost:9000 (usuário: admin, senha: admin)

Agora, configure o scanner em seu projeto. Primeiro, instale o SonarScanner:

# Instalação do SonarScanner (macOS com Homebrew)
brew install sonar-scanner

# Ou no Linux, baixe a versão apropriada
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.8.0.2856-linux.zip
unzip sonar-scanner-cli-4.8.0.2856-linux.zip

Crie um arquivo sonar-project.properties na raiz do projeto:

sonar.projectKey=meu-app
sonar.projectName=Minha Aplicação
sonar.projectVersion=1.0.0
sonar.sources=src
sonar.exclusions=**/*Test.java,**/node_modules/**
sonar.host.url=http://localhost:9000
sonar.login=seu_token_aqui

Execute o scanner:

sonar-scanner

Para integração em GitHub Actions:

name: SonarQube Analysis

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  sonar:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - uses: sonarsource/sonarqube-scan-action@master
        env:
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

      - uses: sonarsource/sonarqube-quality-gate-action@master
        timeout-minutes: 5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

O SonarQube é particularmente útil quando você precisa de análise contínua e histórico de métricas. O dashboard mostra tendências de segurança e qualidade ao longo do tempo, facilitando decisões arquiteturais.

OWASP ZAP: DAST Dinâmico e Interativo

Enquanto SAST analisa código estático, OWASP ZAP (Zed Attack Proxy) é um DAST que testa a aplicação em execução. O ZAP simula ataques reais contra endpoints HTTP, verificando vulnerabilidades como SQL Injection, XSS, CSRF, insecurança em autenticação e muitos outros vetores que só aparecem quando a aplicação está rodando.

O ZAP funciona como um proxy man-in-the-middle (MITM), interceptando requisições e respostas. Ele pode fazer testes passivos (apenas observando tráfego) ou ativos (enviando payloads maliciosos para tentar explorar vulnerabilidades). O OWASP ZAP é gratuito e open-source, com suporte extenso da comunidade.

Existem dois modos principais de usar ZAP: modo GUI (para exploração manual) e modo CLI (para automação em pipelines). Para CI/CD, o modo CLI é mais apropriado. Instale o ZAP:

# No Ubuntu/Debian
sudo apt-get install zaproxy

# Ou via Docker (recomendado para pipelines)
docker run --rm -t owasp/zap2docker-stable zap-baseline.py -t http://seu-app.local

Exemplo de teste baseline com Docker:

#!/bin/bash
# Script para DAST com ZAP

# Inicia a aplicação em background
docker run -d --name app-test -p 8080:8080 seu-app:latest

# Aguarda a aplicação ficar pronta
sleep 10

# Executa ZAP baseline (menos agressivo, mais rápido)
docker run --rm --network host \
  -v $(pwd):/zap/wrk:rw \
  owasp/zap2docker-baseline:latest \
  zap-baseline.py \
  -t http://localhost:8080 \
  -r report.html \
  -J report.json

# Para teste mais profundo, use zap-full-scan.py ao invés

# Limpa
docker stop app-test
docker rm app-test

# Valida resultados (falha se HIGH ou CRITICAL encontrado)
if grep -q '"risk":"High"' report.json || grep -q '"risk":"Critical"' report.json; then
  exit 1
fi

Integração em GitHub Actions com ZAP:

name: OWASP ZAP DAST

on:
  push:
    branches: [ main ]
  schedule:
    - cron: '0 2 * * 0'  # Executar às 2AM aos domingos

jobs:
  zap-scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Start application
        run: |
          docker-compose -f docker-compose.test.yml up -d
          sleep 15

      - name: Run ZAP Scan
        uses: zaproxy/action-baseline@v0.7.0
        with:
          target: 'http://localhost:8080'
          rules_file_name: '.zap/rules.tsv'
          cmd_options: '-a'

      - name: Upload ZAP results
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: zap-report
          path: report_html.html

O ZAP é ideal para testes em ambientes de staging antes de produção. Você consegue detectar vulnerabilidades de lógica de negócio, autenticação quebrada e ataques específicos do contexto da aplicação.

Snyk: SAST Especializado em Dependências

O Snyk é uma plataforma focada em encontrar e corrigir vulnerabilidades em dependências e container images. Enquanto Trivy é mais genérico, Snyk oferece análise mais profunda de bibliotecas, com insights sobre severidade, exploitabilidade real e patches disponíveis. É particularmente forte em ecossistemas como npm, pip, Maven e Gemfile.

Snyk combina dados de múltiplas fontes de vulnerabilidades (NVD, GHSA, banco próprio) para oferecer um quadro mais completo. Além de identificar CVEs, o Snyk verifica se há patches disponíveis e sugere versões seguras imediatamente. A plataforma também integra com repositórios Git, oferecendo pull requests automáticos para patches de segurança.

Instale e configure o Snyk CLI:

# Instalação via npm
npm install -g snyk

# Autenticar com sua conta Snyk
snyk auth

# Testar vulnerabilidades em um projeto
snyk test

# Monitorar continuamente (cria webhook no Git)
snyk monitor

# Testar apenas dependências diretas (excluindo transitivas)
snyk test --strict-out-of-sync=false

Exemplo de uso em um projeto Python:

# Criar um ambiente virtual
python -m venv venv
source venv/bin/activate

# Instalar dependências
pip install -r requirements.txt

# Testar com Snyk
snyk test --file=requirements.txt

# Gerar relatório em JSON
snyk test --json > snyk-report.json

Integração em GitHub Actions:

name: Snyk Security

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  snyk:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Run Snyk to check for vulnerabilities
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

      - name: Upload results to Snyk
        uses: snyk/actions/setup@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        run: snyk monitor

Uma das melhores características do Snyk é a integração automática com repositórios. Você pode configurar Snyk para criar pull requests automaticamente quando patches estão disponíveis:

# Criar token API no dashboard Snyk
# Conectar repositório via https://app.snyk.io

# Snyk gerará PRs automáticas quando:
# - Novos patches forem lançados
# - Novas vulnerabilidades forem descobertas
# - Dependências transitivas forem atualizadas

Snyk é especialmente valioso em ambientes com muitas dependências, onde gerenciar patches manualmente seria impraticável.

Orquestração Integrada: Pipeline Completo

Integrar SAST e DAST em um pipeline único garante cobertura completa. O ideal é executar SAST rapidamente (bloqueia código ruim antes) e DAST em um ambiente mais controlado (testa a aplicação rodando). Aqui está um exemplo realista de pipeline GitLab CI/CD que integra todas as ferramentas:

# .gitlab-ci.yml - Pipeline completo SAST + DAST

stages:
  - build
  - sast
  - docker
  - deploy-staging
  - dast
  - cleanup

variables:
  REGISTRY: registry.gitlab.com
  IMAGE_NAME: $REGISTRY/$CI_PROJECT_PATH

build:
  stage: build
  image: python:3.11
  script:
    - pip install -r requirements.txt
    - python -m pytest tests/ --cov=src
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml

trivy-fs:
  stage: sast
  image: aquasec/trivy:latest
  script:
    - trivy fs --severity HIGH,CRITICAL --format json --output trivy-fs.json .
    - trivy fs --severity HIGH,CRITICAL .
  artifacts:
    reports:
      sast: trivy-fs.json
    when: always

sonarqube:
  stage: sast
  image: sonarsource/sonar-scanner-cli:latest
  script:
    - sonar-scanner
      -Dsonar.projectKey=$CI_PROJECT_NAME
      -Dsonar.sources=src
      -Dsonar.host.url=$SONAR_HOST_URL
      -Dsonar.login=$SONAR_TOKEN
  only:
    - merge_requests
    - main

snyk-test:
  stage: sast
  image: snyk/snyk:python-3.11
  script:
    - snyk test --severity-threshold=high
  env:
    SNYK_TOKEN: $SNYK_TOKEN
  allow_failure: true

docker-build:
  stage: docker
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
    - docker tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:latest
    - docker push $IMAGE_NAME:$CI_COMMIT_SHA
    - docker push $IMAGE_NAME:latest

trivy-image:
  stage: docker
  image: aquasec/trivy:latest
  script:
    - trivy image --severity HIGH,CRITICAL --format json --output trivy-image.json $IMAGE_NAME:$CI_COMMIT_SHA
    - trivy image --severity HIGH,CRITICAL $IMAGE_NAME:$CI_COMMIT_SHA
  dependencies:
    - docker-build
  artifacts:
    reports:
      container_scanning: trivy-image.json
    when: always

deploy-staging:
  stage: deploy-staging
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/app app=$IMAGE_NAME:$CI_COMMIT_SHA -n staging
    - kubectl rollout status deployment/app -n staging
  environment:
    name: staging
    url: https://staging.seu-app.com
  only:
    - main

zap-baseline:
  stage: dast
  image: owasp/zap2docker-stable:latest
  script:
    - sleep 30  # Aguarda deploy estar ready
    - zap-baseline.py
      -t https://staging.seu-app.com
      -r report.html
      -J report.json
      -a  # Enable all scanners
  artifacts:
    paths:
      - report.html
      - report.json
    reports:
      sast: report.json
    when: always
  allow_failure: true
  only:
    - main

cleanup-staging:
  stage: cleanup
  script:
    - echo "Cleanup stage"
  when: always

Este pipeline segue uma ordem lógica: primeiro valida o código (build + testes), depois executa SAST em paralelo (Trivy, SonarQube, Snyk), constrói a imagem Docker e a escaneia, deploya em staging, e finalmente executa DAST contra a aplicação rodando.

Conclusão

Você aprendeu que SAST e DAST são complementares, não substitutos. SAST (Trivy, SonarQube, Snyk) encontra problemas no código e dependências antes da execução, enquanto DAST (OWASP ZAP) testa vulnerabilidades em tempo de execução. A combinação delas em um pipeline CI/CD cria uma defesa em profundidade que bloqueia a maioria dos riscos de segurança.

A escolha de ferramentas deve considerar o contexto: Trivy é leve e rápido para verificações simples, SonarQube é enterprise com histórico e controle fino, Snyk é especializado em dependências com patches automáticos, e OWASP ZAP é essencial para validar comportamento em runtime. Um pipeline maduro integra todas, mas nem todas as organizações precisam de todas simultaneamente.

Por fim, segurança é um processo contínuo. As ferramentas apenas alertam; cabe aos desenvolvedores e arquitetos entender as vulnerabilidades reportadas, priorizar baseado em risco real (não apenas score CVSS), e manter dependências atualizadas. Automação é essencial, mas contexto humano é insubstituível.

Referências


Artigos relacionados