Na era do desenvolvimento de software moderno, é raro construir uma aplicação inteiramente do zero. A maioria dos projetos depende de bibliotecas de código aberto, frameworks e ferramentas de terceiros, criando uma complexa teia de dependências. Essa interconexão, embora aumente a produtividade, também introduz riscos significativos: se um componente upstream for comprometido, todos os projetos que o utilizam podem ser afetados. A segurança da cadeia de suprimentos (supply chain security) visa mitigar esses riscos, garantindo que cada elo da cadeia — desde o código-fonte até o artefato final — seja confiável, rastreável e íntegro.

Nesta aula, vamos explorar quatro pilares fundamentais para proteger sua cadeia de suprimentos: SBOM (Software Bill of Materials), proveniência, assinatura de artefatos e varredura de dependências. Cada um desses conceitos desempenha um papel crucial na construção de um ecossistema de software mais seguro e resiliente. Vamos entender como implementá-los na prática, com exemplos e boas práticas.

SBOM (Software Bill of Materials)

Um SBOM é essencialmente uma lista de ingredientes do seu software — um inventário detalhado de todos os componentes, bibliotecas e dependências que compõem uma aplicação. Assim como a lista de ingredientes em um produto alimentício, o SBOM fornece transparência sobre o que está dentro do software, permitindo que equipes de segurança identifiquem rapidamente componentes vulneráveis quando uma nova vulnerabilidade é divulgada.

O formato mais comum para SBOMs é o CycloneDX, mas também existem outros como SPDX. Esses formatos são legíveis por máquina e podem ser gerados automaticamente por ferramentas de build. A geração de um SBOM deve ser parte integrante do pipeline de CI/CD, garantindo que cada versão do software tenha um SBOM correspondente.

Exemplo de um trecho de SBOM em JSON (formato CycloneDX):

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.4",
  "version": 1,
  "metadata": {
    "component": {
      "type": "application",
      "name": "meu-app",
      "version": "1.0.0"
    }
  },
  "components": [
    {
      "type": "library",
      "name": "lodash",
      "version": "4.17.21",
      "purl": "pkg:npm/lodash@4.17.21"
    },
    {
      "type": "library",
      "name": "express",
      "version": "4.19.2",
      "purl": "pkg:npm/express@4.19.2"
    }
  ]
}

Manter um SBOM atualizado é crucial para a resposta a incidentes. Quando uma vulnerabilidade é descoberta em uma biblioteca, você pode consultar seu SBOM para saber se está usando a versão afetada e em qual aplicação. Além disso, algumas regulamentações e políticas de segurança começam a exigir SBOMs, especialmente em setores críticos como governo e saúde.

Provenance

Proveniência refere-se à origem e ao histórico de um artefato de software. No contexto de supply chain, isso significa ser capaz de rastrear como um artefato foi construído, por quem, a partir de qual código-fonte e com quais parâmetros. Essa informação é vital para estabelecer confiança: você só deve executar software cuja origem você conhece e em que confia.

Ferramentas como SLSA (Supply-chain Levels for Software Artifacts) e in-toto fornecem estruturas para gerar e verificar proveniência. O SLSA define níveis de segurança progressivos (SLSA 1 a 4) que indicam o quão robusto é o pipeline de build. Um nível mais alto inclui builds reproduzíveis, assinaturas criptográficas e autenticação do pipeline.

Um exemplo de declaração de proveniência (em formato JSON, seguindo o padrão SLSA):

{
  "_type": "https://in-toto.io/Statement/v0.1",
  "subject": [
    {
      "name": "meu-app",
      "digest": {
        "sha256": "abc123..."
      }
    }
  ],
  "predicateType": "https://slsa.dev/provenance/v0.2",
  "predicate": {
    "builder": {
      "id": "https://github.com/meu-org/meu-app/actions"
    },
    "buildType": "https://github.com/meu-org/meu-app/actions/workflows/build.yml@refs/heads/main",
    "invocation": {
      "configSource": {
        "uri": "git+https://github.com/meu-org/meu-app.git",
        "digest": {
          "sha1": "f1a2b3c4..."
        }
      }
    }
  }
}

Implementar proveniência envolve configurar seu pipeline de CI para gerar esses metadados e assiná-los. Isso permite que qualquer pessoa verifique que o artefato foi construído por um processo confiável, reduzindo o risco de artefatos maliciosos ou adulterados.

Signing

Assinatura de artefatos é o processo de aplicar uma assinatura criptográfica a um arquivo ou pacote para garantir sua integridade e autenticidade. Ao assinar um artefato, você fornece uma prova de que ele não foi alterado desde que foi assinado e que veio de uma fonte legítima (se a chave privada for mantida em segurança).

Ferramentas como GPG, Sigstore/cosign e Minisign são comuns para assinar containers, binários e até pacotes de dependências. O Sigstore, por exemplo, oferece assinatura sem a necessidade de gerenciar chaves complexas, usando identidades de e-mail e OIDC. Cosign é uma ferramenta para assinar e verificar imagens de containers.

Exemplo de assinatura de imagem de container com cosign:

# Gerar um par de chaves (ou usar o fluxo de identidade)
cosign generate-key-pair

# Assinar a imagem
cosign sign --key cosign.key meu-registry/meu-app:latest

# Verificar a assinatura
cosign verify --key cosign.pub meu-registry/meu-app:latest

Assinar não é apenas para distribuição externa; também é útil internamente. Ao assinar artefatos em cada etapa do pipeline, você pode verificar se o que está sendo promovido para produção é exatamente o que passou pelos testes e verificações de segurança.

Dependency scanning

Varredura de dependências é o processo de analisar as dependências do seu projeto em busca de vulnerabilidades conhecidas, licenças problemáticas ou outros riscos. Ferramentas como Snyk, OWASP Dependency-Check, Trivy e GitHub Dependabot automatizam essa análise, comparando as versões das dependências com bancos de dados de vulnerabilidades (CVE).

Integrar a varredura de dependências no pipeline de CI é fundamental para impedir que vulnerabilidades conhecidas cheguem à produção. Quando uma nova vulnerabilidade é divulgada, essas ferramentas podem alertar automaticamente ou até mesmo abrir pull requests para atualizar a dependência para uma versão corrigida.

Exemplo de uso do OWASP Dependency-Check em um pipeline (comando simples):

# Instalar a ferramenta (exemplo em um ambiente Linux)
wget https://github.com/jeremylong/DependencyCheck/releases/download/v9.0.0/dependency-check-9.0.0-release.zip
unzip dependency-check-9.0.0-release.zip

# Executar a varredura no projeto
dependency-check/bin/dependency-check.sh --project "Meu Projeto" --scan . --format HTML

Além de vulnerabilidades, a varredura de dependências também pode verificar se as dependências estão atualizadas e se há versões mais recentes com correções de segurança. É importante lembrar que a varredura é uma fotografia momentânea; por isso, deve ser executada regularmente, não apenas uma vez.

Boas práticas e observações finais

Para uma cadeia de suprimentos robusta, combine todos esses elementos: gere SBOMs automaticamente, assine seus artefatos, mantenha proveniência verificável e faça varredura contínua de dependências. Além disso, adote políticas de atualização de dependências, minimize o uso de dependências desnecessárias e monitore ativamente os avisos de segurança das fontes oficiais. Lembre-se de que a segurança da cadeia de suprimentos é um processo contínuo, não um destino.

Referências

Exercícios

  1. Explique o que é um SBOM e por que ele é importante para a segurança da cadeia de suprimentos. Dê um exemplo de um formato comum de SBOM.

    ✓ Resposta: Um SBOM (Software Bill of Materials) é uma lista detalhada de todos os componentes, bibliotecas e dependências que compõem um software. Ele é importante porque permite identificar rapidamente quais componentes estão vulneráveis quando uma nova vulnerabilidade é divulgada, facilitando a resposta a incidentes e a conformidade com regulamentações. Formatos comuns incluem CycloneDX e SPDX, que são legíveis por máquina e podem ser gerados automaticamente durante o build.
  2. O que significa proveniência no contexto de segurança de supply chain? Como o SLSA ajuda a estabelecer confiança?

    ✓ Resposta: Proveniência refere-se à origem e ao histórico de um artefato de software, incluindo como foi construído, por quem e a partir de qual código-fonte. O SLSA (Supply-chain Levels for Software Artifacts) define níveis de segurança progressivos (SLSA 1 a 4) que indicam o quão robusto é o pipeline de build. Níveis mais altos exigem builds reproduzíveis, assinaturas criptográficas e autenticação do pipeline, o que aumenta a confiança na origem e integridade do artefato.
  3. Qual é o objetivo da assinatura de artefatos? Cite duas ferramentas utilizadas para assinar artefatos e explique brevemente como funcionam.

    ✓ Resposta: O objetivo da assinatura de artefatos é garantir a integridade e autenticidade de um arquivo ou pacote, provando que ele não foi alterado e que provém de uma fonte legítima. Duas ferramentas são GPG (GNU Privacy Guard) e cosign (parte do Sigstore). GPG usa um par de chaves público/privada para assinar e verificar arquivos. Cosign é projetado para assinar imagens de containers, podendo usar identidades OIDC (como e-mail) para simplificar o gerenciamento de chaves, e é integrado a registries de containers.
  4. Descreva o que é dependency scanning e cite três ferramentas que realizam essa tarefa. Por que é importante executar essa varredura regularmente?

    ✓ Resposta: Dependency scanning é o processo de analisar as dependências de um projeto em busca de vulnerabilidades conhecidas, problemas de licença ou outros riscos. Ferramentas como Snyk, OWASP Dependency-Check e GitHub Dependabot automatizam essa análise. É importante executar a varredura regularmente porque novas vulnerabilidades são descobertas constantemente, e a varredura é uma fotografia momentânea; sem varreduras periódicas, você pode ficar exposto a vulnerabilidades recém-divulgadas sem saber.
  5. Explique como você integraria as quatro práticas (SBOM, proveniência, signing e dependency scanning) em um pipeline de CI/CD. Dê um exemplo de fluxo.

    ✓ Resposta: Um fluxo integrado poderia ser: 1) Durante o build, gerar o SBOM usando uma ferramenta como CycloneDX; 2) Executar a varredura de dependências (ex.: Snyk) e falhar o build se houver vulnerabilidades críticas; 3) Assinar o artefato (ex.: cosign) e gerar a proveniência (ex.: SLSA) com metadados do pipeline; 4) Publicar o SBOM, a assinatura e a proveniência junto com o artefato no registro. Isso garante rastreabilidade, integridade e conformidade em todo o ciclo.