Dependência-Confusão-Versão-Fixação

Falta de fixação de versão e confusão de dependências

No desenvolvimento de software dependemos de componentes ou artefatos próprios e de terceiros. Um gerenciamento de dependências flexível é essencial para software moderno. Gerenciadores de pacotes como NPM, Mavenpip or NuGet são frequentemente usados ​​para especificar dependências de software. Essas ferramentas foram projetadas pensando na conveniência e facilidade de uso, não na segurança.

 

O problema

O problema é que a flexibilidade e a facilidade de uso dos desenvolvedores chamam os bandidos, que veem as dependências de software como um charme irresistível para seus negócios. O resultado: os malfeitores seguiram todos os caminhos de ataque possíveis mostrados aqui. Fonte: “Coleção de facas do Backstabber: uma revisão dos ataques à cadeia de suprimentos de software de código aberto”

Neste post vamos focar no uso de declarações de versão aberta, no sentido de que a versão baixada não é fixa, mas deve pertencer a um determinado intervalo. No momento da construção, a versão existente mais alta compatível com o intervalo de versões especificado é escolhida e baixada/instalada pelo gerenciador de pacotes.

Vamos ilustrar declarações abertas em declarações de dependências para diferentes gerenciadores de pacotes:

      • NPM: package.json

    {

     

       ...

       “dependências”: {
          ...
          “aceita”: “>=1.3.8”,
          “lodash”: “~4.16.0”,
          ...
       },
       ...
    }

    A maior versão existente não inferior a 1.3.8 para o pacote aceita será instalada, bem como a maior atualização de 'patch' para lodash na faixa 4.16.x.

        • Especialista: pom.xml

      ...

      ...

           commons-io
           comum-io
           LIBERAR

      ...

      ...

      A última versão disponível para o commons-io (arquivo jar) será adicionada como dependência.

          • Pip: setup.py

        ...
        configurar(
            ...
            install_requires=['pimenta em grão', 'launchpadlib'],
            ...
        )
        ...

        Esses esquemas de versão aberta têm um lado bom e um lado ruim. O bom é que as versões mais recentes geralmente contêm melhorias funcionais e de qualidade, correções de bugs e patches de segurança, que são atualizados automaticamente. Observe que, para a maioria dos projetos do mundo real, as correções não são retroportadas para versões secundárias anteriores, exceto talvez para vulnerabilidades de segurança catastróficas. Versões abertas também são boas para uso em bibliotecas, para reduzir o número de versões que precisam ser instaladas quando todas as dependências forem resolvidas.

        Mas as faixas de versões abertas têm um lado ruim. Você não sabe exatamente quais versões serão instaladas no momento da compilação e as compilações não são repetíveis. E há também um escuro lado com versões abertas. Se um malfeitor conseguir publicar um componente malicioso no repositório público com uma versão alta compatível com seu alcance aberto, sua próxima compilação incluirá o componente malicioso, talvez até executando malware em scripts de instalação que podem ser executados automaticamente. Ofuscar a carga útil do ataque é uma arte.

        Isto é conhecido como o Falta de fixação de versão questão.

        Atores mal-intencionados estão sempre tentando colocar versões maliciosas de pacotes populares de código aberto. Eles podem obter acesso às chaves para repositórios de pacotes em um vazamento secreto; eles geralmente usam engenharia social ou escondem uma dependência maliciosa aninhada em um aparentemente útil pull request. Até mesmo alguns autores decidem um dia que o mundo não é justo e mordem seus clientes com protesto em seus próprios pacotes!

        Agora imagine que você trabalha para uma organização que usa componentes internos e também de código aberto.
        Se um malfeitor souber o nome de tais componentes internos, ele poderá publicar um componente com o mesmo nome no repositório público. Muitos gerenciadores de pacotes obtêm primeiro os componentes públicos e, se a versão for escolhida corretamente e a versão na sua dependência declarada estiver aberta, bum! Este problema é nomeado Confusão de Dependência.

        Vamos mostrar um exemplo. Suponha que em nosso projeto NPM tenhamos uma dependência de um componente privado:

            • NPM: package.json

          {
            "nome": "meu-projeto",

           

            ...
            “dependências”: {

              ...
              “meu-privado-dep”: “>=1.0.0”,

              ...

             }

             ...

          }

           

          O invasor pode criar uma versão principal de my-private-dep (como 99.0.0) e publicá-la no repositório npm público, com sua própria conta falsa (o invasor não precisa fazer nada com minha organização). O gerenciador de pacotes NPM instalará a dependência maliciosa, muitas vezes com resultados devastadores.

          A solução

          Para evitar esses problemas em nosso processo de construção de software, devemos seguir normas rígidas sobre como declarar versões de componentes, que dependem da tecnologia utilizada. O importante é que uma versão específica de um pacote, uma vez publicada em um repositório, seja imutável (para evitar quebra de dependentes, não apenas por questões de segurança).

          A ideia geral é fixar (pino), sempre verificando se as versões fixas dos componentes (incluindo TODAS as dependências transitivas) estão livres de malware, e isso é possível graças ao arquivos de bloqueio que muitos gerenciadores de pacotes oferecem. Vamos ver como funciona a fixação de versão para diferentes gerenciadores de pacotes. Há uma troca delicada entre atualizações frequentes de versão para corrigir vulnerabilidades conhecidas e fixação de versão para evitar construções não determinísticas e possíveis ataques à cadeia de suprimentos.

              • NPM:
                Os gerenciadores de pacotes npm ou yarn usam diferentes lockfiles (npm-shrinkwrap.json / package-lock.json ou yarn.lock, respectivamente) que listam versões fixas para todas as dependências, diretas e indiretas. Os lockfiles devem estar sob controle de versão, caso contrário, outros desenvolvedores/nós de construção podem terminar com versões diferentes. Evite npm install, a menos que durante o desenvolvimento você precise atualizar as dependências (por exemplo, para instalar correções de segurança). Use o npm ci (instalação limpa) mais determinístico em geral, para que o gerenciador de pacotes use o arquivo de bloqueio ou encerre com erro se não houver arquivo de bloqueio ou se não corresponder ao package.json. Se as versões listadas foram verificadas em busca de malware, o arquivo de bloqueio garante que nada de ruim acontecerá no momento da compilação.

                Para componentes internos, é recomendável criar um Escopo do NPM gerenciado pela organização (como @myorg) e usar esse escopo na dependência (como @myorg/my-private-dep), que poderia ter apenas visibilidade privada. Isso bloqueia confusão de dependência ataques, já que apenas membros da organização com acesso de gravação podem publicar pacotes sob tal escopo.

              • Maven:
                Maven/Gradle não possui lockfiles (mas veja este artigo StackOverflow).

                Os intervalos de versões não são usados ​​com Maven/Gradle tanto quanto com outros ecossistemas. Apenas evite intervalos de versão e meta-versões LATEST ou RELEASE. Versões indiretas também devem ser verificadas. O Versões do plugin Maven é uma ótima ferramenta para controle de versão.

                Observe que o Maven sempre teve o conceito de escopo de organização (a parte groupId da dependência), e a confusão de dependências parece não ser um problema para esse ecossistema.

              • Pip:
                Em Python existem diferentes ferramentas para lidar com lockfiles:

                pipenv, que gera um arquivo de bloqueio Pipfile.lock.
                poesia, que gera poesia.lock.
                pip congelar, comando que gera um requirements.txt que atua como um arquivo de bloqueio. Verifique se todas as dependências usam versões fixas com o operador ==. Então pip install -r requisitos.txt usa as dependências fixas.

            Lembre-se de que os arquivos de bloqueio acima devem estar sob controle de versão e que o comando de construção escolhido deve usar o arquivo de bloqueio.

            O repositório de pacotes usual usado com pip (PyPI) não possui escopos de nomenclatura e é vulnerável a ataques de confusão de dependência. Evitando confusão de dependências no ecossistema python não é fácil, e alguns autores recomendam usar um repositório interno para atuar como um proxy para dependências públicas obtidas do PyPI, mas pegar primeiro as dependências privadas do repositório interno (-index-url deve apontar para o repositório interno, não para o PyPI, e –extra-index-url deve ser removido).

            Alguns ataques reais

            Ataque Getcookies: O ator dustin87 adicionou uma dependência indireta do popular pacote npm mailparser a um pacote malicioso com backdoor RCE (gCOMMANDhDATAi):

            JSON.stringify(req.headers).replace(/g([a-f0-9]{4})h((?:[a-f0-9]{2})+)i/gi, (o, p, v) => {})

            Apesar de ter sido descontinuado (sem revisores!), o mailparser ainda recebeu cerca de 64,000 downloads semanais. Este foi um caso de um ataque quase fatal, pois o RCE não foi realmente exercidocised.

            NPM publicado esta postagem com detalhes sobre o ataque getcookies.

            Confusão de Dependência:

            Alex Birsan descobriu em 2021 o problema de confusão de dependência e publicou um post intitulado “Como invadi a Apple, a Microsoft e dezenas de outras empresas".

            Lembre-se de que para o npm o escopo da organização como @myorg deve ser reservado e os pacotes internos devem ser modificados para usar o escopo.

            Com o pip, o registro público comum PyPI não possui escopos/namespaces. Cada pacote privado pode ter um pacote público com o mesmo nome do pacote interno, mas vazio, e talvez gerando um erro quando usado, para que possa ser identificado se for obtido acidentalmente.

            Nó-ipc:

            O proprietário do pacote, quando a guerra Rússia-Ucrânia começou, injetou código malicioso para remover arquivos aleatórios, quando instalado em hosts russos e bielorrussos. O arquivo ssl-geospec.js estava fazendo essa distinção geográfica:

            Curiosamente, outros pacotes usaram versões abertas para a dependência node-ipc, como o popular framework Vue.js, e seus mantenedores receberam um apelo urgente para fixar a dependência node-ipc em uma versão segura.

            Esta postagem contém mais detalhes nesta sabotagem, que vai um passo além de outras Software de protesto problemas.

             

            Observações finais

            Versões abertas devem nunca ser usado em projetos de software consolidados. Eles tornam as compilações não reproduzíveis e os invasores podem explorá-las e conseguir injetar malware por meio de ataques às árvores de dependência, como a confusão de dependência mencionada acima.

            Configurações incorretas como versões abertas, falta de fixação de versão ou componentes internos sem escopo Deveria ser evitado. A primeira coisa é detectar tais problemas, talvez até mesmo bloquear a construção quando forem encontrados, e padronizar um protocolo de ação.

            Detecção automática de falhas e configurações incorretas em dependências, reportando dependências suspeitas que poderiam ser vulneráveis ​​a ataques específicos à cadeia de suprimentos, como confusão de dependência, todos com ferramentas de correção acionáveis, é um dos principais objetivos do Plataforma Xygeni.

            Para ler mais
            Ohm M., Plate H., Sykosch A., Meier M.: “Coleção de facas do Backstabber: uma revisão dos ataques à cadeia de suprimentos de software de código aberto”. DIMVA 2020. Lecture Notes in Computer Science, vol 12223. Springer – 2020 (fonte da figura da árvore de ataque de dependência.)
            @adam-npm: “Módulo malicioso relatado: getcookies“. Blog npm (arquivado) – 2 de maio de 2018.
            Alex Birsan: “Como invadi a Apple, a Microsoft e dezenas de outras empresas”. Médio – 9 de fevereiro de 2021.
            Machado Sharma: “GRANDE sabotagem: famoso pacote npm exclui arquivos para protestar contra a guerra na Ucrânia” BleepingComputer – 17 de março de 2022

            sca-tools-software-composição-análise-ferramentas
            Priorize, corrija e proteja seus riscos de software
            você recebe uma avaliação gratuita de 7 dias da nossa licença Business Edition e pode aproveitar alguns dos recursos avançados da plataforma SecurityScorecard.
            Não é necessário cartão de crédito

            Proteja seu desenvolvimento e entrega de software

            com o Suíte de Produtos da Xygeni