Melhores práticas para uma cadeia de fornecedores de software segura

O código aberto está em toda parte. Ele está em muitas bases de código proprietárias e projetos comunitários. Para organizações e indivíduos, a questão hoje não é se você está ou não usando código aberto, mas qual e quanto código aberto você está usando.

Se você não estiver ciente do que está em sua cadeia de suprimentos de software, uma vulnerabilidade upstream em uma de suas dependências poderá ser fatal, tornando você e seus clientes vulneráveis a um possível comprometimento. Neste documento, vamos nos aprofundar no que o termo "cadeia de suprimentos de software" significa, por que ele é importante e como você pode ajudar a proteger a cadeia de suprimentos do seu projeto seguindo as melhores práticas.

The State of the Octoverse 2020 - Open Source

Dependências

O termo cadeia de suprimentos de software é usado para se referir a tudo o que faz parte do seu software e de onde isso vem. São das dependências e propriedades de suas dependências que sua cadeia de suprimentos de software depende. Uma dependência é o que seu software precisa para executar. Ela pode existir na forma de código, binários ou outros componentes, e de onde eles vêm, como um repositório ou gerenciador de pacotes.

Ela inclui quem escreveu o código, quando ele foi contribuído, como ele foi revisado em busca de problemas de segurança, vulnerabilidades conhecidas, versões compatíveis, informações de licença e praticamente qualquer coisa que a toque em qualquer ponto do processo.

Sua cadeia de suprimentos também abrange outras partes de sua pilha além de um único aplicativo, como seus scripts de compilação e empacotamento ou o software que executa a infraestrutura da qual seu aplicativo depende.

Vulnerabilidades

Hoje, as dependências de software são generalizadas. É bastante comum que seus projetos usem centenas de dependências de código aberto para funcionalidades que você mesmo não precisa escrever. Isso pode significar que a maior parte do seu aplicativo consiste em código que não foi criado por você.

The State of the Octoverse 2020 - Dependencies

Possíveis vulnerabilidades em suas dependências de terceiros ou de código aberto são, presumivelmente, dependências que você não pode controlar tão rigorosamente quanto o código que você escreve, o que pode criar riscos potenciais de segurança em sua cadeia de suprimentos.

Se uma dessas dependências apresenta uma vulnerabilidade, há grandes chances de você também ter uma vulnerabilidade. Isso pode ser assustador, pois uma de suas dependências pode mudar sem que você saiba. Mesmo que uma vulnerabilidade exista em uma dependência hoje, mas não seja explorável, ela pode ser explorável no futuro.

Ser capaz de reutilizar o trabalho de milhares de desenvolvedores de código aberto e autores de bibliotecas significa que milhares de estranhos podem efetivamente contribuir diretamente para o seu código de produção. Seu produto, por meio de sua cadeia de suprimentos de software, é afetado por vulnerabilidades não corrigidas, erros inocentes ou até mesmo ataques maliciosos contra dependências.

Compromissos da cadeia de suprimentos

A definição tradicional de cadeia de suprimentos vem da manufatura; é a cadeia de processos necessários para fazer e fornecer algo. Inclui planejamento, fornecimento de materiais, fabricação e varejo. Uma cadeia de suprimentos de software é semelhante, exceto que, em vez de materiais, é composta por código. Em vez de fabricação, é desenvolvimento. Em vez de extrair minério do solo, o código é proveniente de fornecedores, comerciais ou de código aberto, e, em geral, o código-fonte aberto vem de repositórios. Adicionar código de um repositório significa que seu produto passa a depender desse código.

Um exemplo de ataque à cadeia de suprimentos de software ocorre quando um código mal-intencionado é adicionado propositalmente a uma dependência, usando a cadeia de suprimentos dessa dependência para distribuir o código para suas vítimas. Os ataques à cadeia de suprimentos são reais. Existem muitos métodos para atacar uma cadeia de suprimentos, desde inserir diretamente código malicioso como um novo contribuidor, assumir a conta de um contribuidor sem que outros percebam ou até mesmo comprometer uma chave de assinatura para distribuir software que não é oficialmente parte da dependência.

Um ataque à cadeia de suprimentos de software raramente é o objetivo final, mas sim o início de uma oportunidade para um invasor inserir malware ou fornecer um backdoor para acesso futuro.

The State of the Octoverse 2020 - Vulnerability Lifecycle

Software sem patches

O uso de código aberto hoje é significativo e não deve desacelerar tão cedo. Considerando que não vamos parar de usar software de código aberto, a ameaça à segurança da cadeia de suprimentos é o software sem patch. Sabendo disso, como você pode lidar com o risco de uma dependência do seu projeto ter uma vulnerabilidade?

  • Sabendo o que está no seu ambiente. Isso requer descobrir suas dependências e quaisquer dependências transitivas para entender os riscos dessas dependências, como vulnerabilidades ou restrições de licenciamento.
  • Gerencie suas dependências Quando uma nova vulnerabilidade de segurança é descoberta, determine se você é afetado e, em caso afirmativo, atualize para a versão e o patch de segurança mais recentes disponíveis. Isso é especialmente importante para revisar alterações que introduzem novas dependências ou auditar periodicamente dependências antigas.
  • Monitore sua cadeia de suprimentos. Isso ocorre auditando os controles vigentes para gerenciar suas dependências. Isso ajudará você a impor condições mais restritivas que devem atendidas para suas dependências.

The State of the Octoverse 2020 - Advisories

Abordaremos várias ferramentas e técnicas que o NuGet e o GitHub fornecem, as quais você pode usar hoje para abordar riscos potenciais dentro do seu projeto.

Sabendo o que está no seu ambiente

Grafo de dependência do NuGet

📦 Consumidor de pacotes

Você pode exibir suas dependências do NuGet em seu projeto observando diretamente o respectivo arquivo de projeto.

Isso normalmente é encontrado em um dos dois lugares:

Dependendo do método usado para gerenciar suas dependências do NuGet, você também pode usar o Visual Studio para exibir suas dependências diretamente no Gerenciador de Soluções ou no Gerenciador de Pacotes NuGet.

Para ambientes de CLI, você pode usar o comando dotnet list package para listar as dependências do projeto ou da solução.

Para obter mais informações sobre como gerenciar dependências do NuGet, consulte a documentação a seguir.

Grafo de dependência do GitHub

📦 Consumidor de pacotes| 📦🖊 Autor de pacotes

Você pode usar o grafo de dependência para ver os pacotes dos quais o projeto depende e os repositórios que dependem dele. Isso pode ajudar você a ver todas as vulnerabilidades detectadas em suas dependências.

Para obter mais informações sobre as dependências do repositório do GitHub, consulte a documentação a seguir.

Versões de dependências

📦 Consumidor de pacotes| 📦🖊 Autor de pacotes

Para garantir uma cadeia de suprimentos de dependências segura, é necessário garantir que todas as suas dependências e ferramentas sejam atualizadas regularmente para a versão estável mais recente, pois elas geralmente incluem a funcionalidade e os patches de segurança para as vulnerabilidades conhecidas mais recentes. Suas dependências podem incluir código do qual você depende, binários que você consome, ferramentas que você usa e outros componentes. Isso pode incluir:

Gerenciar as dependências

Dependências obsoletas e vulneráveis do NuGet

📦 Consumidor de pacotes| 📦🖊 Autor de pacotes

Você pode usar a CLI do dotnet para listar quaisquer dependências obsoletas ou vulneráveis conhecidas que você possa ter dentro de seu projeto ou solução. Você pode usar o comando dotnet list package --deprecated ou dotnet list package --vulnerable para fornecer uma lista de obsolescências ou vulnerabilidades conhecidas.

Dependências vulneráveis do GitHub

📦 Consumidor de pacotes| 📦🖊 Autor de pacotes

Se o seu projeto estiver hospedado no GitHub, você poderá utilizar o GitHub Security para encontrar vulnerabilidades e erros de segurança em seu projeto e o Dependabot os corrigirá abrindo uma pull request em sua base de código.

Capturar dependências vulneráveis antes que elas sejam introduzidas é um dos objetivos do movimento "Shift Left". Ser capaz de ter informações sobre suas dependências, como sua licença, dependências transitivas e a idade das dependências ajuda você a fazer exatamente isso.

Para obter mais informações sobre alertas do Dependabote e atualizações de segurança, confira a documentação a seguir.

Feeds NuGet

📦 Consumidor de pacotes

Quando vários feeds de origem NuGet públicos e privados são usados, um pacote pode ser baixado de qualquer um dos feeds. Para garantir que sua compilação seja previsível e segura contra ataques conhecidos, como Confusão de dependência, saber de quais feeds específicos seus pacotes estão vindo é uma melhor prática. Você pode usar um único feed ou feed privado com recursos de upstreaming para proteção.

Para obter mais informações sobre como proteger seus feeds de pacotes, consulte Três Maneiras de Atenuar o Risco ao Usar Feeds de Pacotes Privados.

Ao usar um feed privado, confira as melhores práticas de segurança para gerenciar credenciais.

Políticas de confiança do cliente

📦 Consumidor de pacotes

Há políticas que você pode aceitar nas quais você exige que os pacotes usados sejam assinados. Isso permite que você confie em um autor de pacote, desde que ele seja assinado pelo autor ou confie em um pacote se ele for pertencente a um usuário ou conta específica que é repositório assinado por NuGet.org.

Para configurar políticas de confiança do cliente, consulte a documentação a seguir.

Arquivos de bloqueio

📦 Consumidor de pacotes

Os arquivos de bloqueio armazenam o hash do conteúdo do seu pacote. Se o hash de conteúdo de um pacote que você deseja instalar corresponder ao arquivo de bloqueio, ele garantirá a repetibilidade do pacote.

Para habilitar arquivos de bloqueio, consulte a documentação a seguir.

Mapeamento de origens de pacotes

📦 Consumidor de pacotes

O mapeamento de origens de pacotes permite que você declare centralmente em seu arquivo nuget.config de qual origem cada pacote em sua solução deve ser restaurado.

Para habilitar o mapeamento de origem do pacote, consulte a documentação a seguir.

Monitore sua cadeia de suprimentos

Verificação de segredo do GitHub

📦🖊 Autor do pacote

O GitHub verifica os repositórios em busca de chaves de API do NuGet para evitar o uso fraudulento de segredos cujo commit foi feito acidentalmente.

Para saber mais sobre a verificação secreta, consulte Sobre a verificação secreta.

Assinatura do pacote do autor

📦🖊 Autor do pacote

A assinatura do autor permite que um autor de pacote carimbe sua identidade em um pacote e que um consumidor verifique se ele veio de você. Isso protege você contra adulteração de conteúdo e serve como uma única fonte de verdade sobre a origem do pacote e a autenticidade do pacote. Quando combinado com políticas de confiança do cliente, você pode verificar se um pacote veio de um autor específico.

Para assinar um pacote com o autor, consulte Assinar um pacote.

Compilações reproduzíveis

📦🖊 Autor do pacote

Compilações reproduzíveis criam binários que são byte por byte idênticos cada vez que você os compila e contêm links de código-fonte e metadados do compilador que permitem que um consumidor de pacote recrie o binário diretamente e valide que o ambiente de compilação não foi comprometido.

Para saber mais sobre compilações reproduzíveis, consulte Produzindo pacotes com link de origem e a especificação Validação de compilação reproduzível.

Autenticação de dois fatores (2FA)

📦🖊 Autor do pacote

Toda conta no nuget.org tem a 2FA habilitada. Isso adiciona uma camada extra de segurança ao fazer login em sua conta do GitHub ou em sua conta do NuGet.org.

Reserva de prefixo da ID do pacote

📦🖊 Autor do pacote

Para proteger a identidade de seus pacotes, você pode reservar um prefixo de ID de pacote com seu respectivo namespace para associar um proprietário correspondente se o prefixo de ID do pacote se enquadrar corretamente nos critérios especificados.

Para saber mais sobre como reservar prefixos de ID, consulte Reserva de prefixo de ID de pacote.

Substituindo e removendo um pacote vulnerável da lista

📦🖊 Autor do pacote

Para proteger o ecossistema de pacotes do .NET quando você estiver ciente de uma vulnerabilidade em um pacote que criou, faça o possível para preterir e remover da lista o pacote para que ele seja ocultado dos usuários que procuram pacotes. Se você estiver consumindo um pacote que foi preterido e não listado, evite usá-lo.

Para saber como preterir e remover da lista de um pacote, consulte a documentação a seguir sobre como preterir e remover pacotes da lista.

Resumo

Sua cadeia de suprimentos de software é qualquer coisa que entra ou afeta seu código. Mesmo que os comprometimentos da cadeia de suprimentos sejam reais e cresçam em popularidade, eles ainda são raros. Portanto, a coisa mais importante que você pode fazer é proteger sua cadeia de suprimentos é estar ciente de suas dependências, gerenciar suas dependências e monitorar sua cadeia de suprimentos.

Você aprendeu sobre vários métodos que o NuGet e o GitHub fornecem e que estão disponíveis hoje para serem mais eficazes na exibição, no gerenciamento e no monitoramento da sua cadeia de suprimentos.

Para obter mais informações sobre como proteger software no mundo, consulte o Relatório de Segurança O Estado do Octoverse 2020.