7 Dicas para Evitar ser Hackeado (npm, pnpm e bun)

BBetter Stack
컴퓨터/소프트웨어AI/미래기술

Transcript

00:00:00Se você instala pacotes NPM, você é um alvo. Talvez não hoje, talvez não esta semana, mas é
00:00:05definitivamente algo que vai acontecer. Tivemos centenas de pacotes comprometidos só nos últimos meses,
00:00:09e isso não está diminuindo. Então, em vez de me preocupar cada vez que algo assim acontece,
00:00:14eu resolvi bloquear minha própria configuração no NPM, PNPM e BUN, e acontece que a maioria
00:00:18das coisas que teriam te salvado leva cerca de 30 segundos para configurar. Então, neste vídeo,
00:00:23vou te mostrar as sete mudanças que fiz, desde uma única linha de alteração de configuração que
00:00:27elimina o ataque mais comum, até ferramentas gratuitas que os próprios atacantes enviaram
00:00:30que os pegariam antes mesmo que o pacote chegasse à sua máquina. Vamos lá.
00:00:39A primeira e mais simples é apenas parar de baixar pacotes novos. A maioria desses ataques à cadeia
00:00:44de suprimentos é descoberta em poucas horas, então se você simplesmente não instalar versões novas no segundo
00:00:48em que forem lançadas, você na verdade evita a maioria desses ataques à cadeia de suprimentos completamente. Todos os principais
00:00:52gerenciadores de pacotes do Node.js oferecem agora alguma forma de controle por idade de lançamento. Para o NPM, você define isso no arquivo
00:00:57.npmrc, e é definido em dias. Para o PNPM, você pode definir globalmente no arquivo pnpm-config.yaml,
00:01:03ou pode definir isso por projeto usando o arquivo pnpm-workspace.yaml, e este valor é na verdade
00:01:08definido em minutos. E também vale notar que desde o PNPM 11, isso tem um padrão de um dia,
00:01:14então mesmo que você não defina, você ainda tem alguma proteção. Para o BUN, você define isso no
00:01:17bunfig.toml, seja globalmente ou novamente por projeto, e este é definido em segundos.
00:01:23Realmente me surpreende que, para três gerenciadores de pacotes com a mesma configuração, tenhamos chegado a
00:01:27três valores diferentes, e isso resume bem como é este ecossistema. Assim que você tiver isso configurado,
00:01:32se você tentar instalar um pacote como o react-start do TanStack, você verá que ele não instala a
00:01:36versão mais recente, ele na verdade instala a mais recente que se encaixa no meu critério de idade de lançamento, que para mim
00:01:41era de uma semana atrás. Agora, se você precisar ignorar isso, talvez porque tenha havido um problema de segurança no
00:01:45pacote que você está instalando e precise instalar a versão mais recente, você ainda pode fazer isso
00:01:49pela linha de comando, mas cuidado com LLMs aqui também, pois já vi casos em que LLMs
00:01:54apenas usam isso para ignorar e instalar as versões mais recentes de qualquer maneira. Outra coisa para manter em mente é
00:01:59que NPX e BUNX não respeitam essa configuração, eles na verdade ainda instalam a versão mais recente,
00:02:03e existe um PR aberto no BUN para corrigir isso. Agora, enquanto estamos nessas configurações, vamos
00:02:07também desativar scripts de instalação para o NPM. PNPM e BUN já têm esse comportamento por padrão,
00:02:12então não há nada para configurar para eles. Se você não sabia, quando você instala um pacote, esse pacote
00:02:16tem permissão para executar seu próprio código logo após a instalação, e isso foi feito para casos de uso
00:02:20legítimos, como compilar código nativo ou baixar um binário, mas o problema é que quase todo
00:02:26ataque à cadeia de suprimentos usou esse método para executar código malicioso na sua máquina logo após a instalação.
00:02:30Se você encontrar um pacote que tem uma necessidade legítima de um desses scripts, você ainda pode habilitá-lo explicitamente.
00:02:34No PNPM, quando você instala um pacote que tem scripts de pós-instalação, ele te avisará,
00:02:39como o esbuild aqui, e então você pode executar "pnpm approved-builds" para escolher quais permitir,
00:02:44e isso na verdade define sua configuração "pnpm-workspace-allow-builds", e você também pode simplesmente usar a
00:02:48flag "--allow-build" no comando de instalação para fazer a mesma coisa. Para o BUN, como eu disse, ele impede esses
00:02:52scripts de instalação por padrão também, mas vale saber que ele tem uma lista com curadoria de
00:02:56pacotes autorizados a executar esses scripts, e isso inclui alguns que instalei, como o
00:03:00esbuild. Você pode desativar isso adicionando "trusted-dependencies" no seu package.json,
00:03:04dessa forma apenas os pacotes que você permitir explicitamente poderão executar scripts de pós-instalação.
00:03:09Diz também que se você definir o array como vazio, ele deve substituir essa lista padrão
00:03:12também, mas não parece estar funcionando para mim, e parece ser um bug que encontrei no GitHub
00:03:17também. A solução alternativa no momento é apenas colocar um valor nessa lista, e então a lista padrão
00:03:21é ignorada. Com o BUN, você também pode executar "bun pm untrusted" para ver quais pacotes querem executar
00:03:26scripts, mas ainda não são confiáveis, e então você pode executar "bun pm trust" para permitir um, ou apenas adicioná-lo àquela
00:03:30lista de "trusted-dependencies". Você também pode desativar totalmente os scripts no BUN definindo "install-scripts" para
00:03:35false no seu arquivo global de configuração do BUN. Para o NPM, isso é um pouco mais difícil. Honestamente, apenas não use
00:03:40NPM, use PNPM, mas se você realmente precisar usar o NPM por algum motivo, você pode obter um comportamento de lista de permissões
00:03:45similar usando o pacote "Lavamote's allow-scripts" para NPM. Dessa forma, é apenas uma lista de permissões no seu
00:03:50package.json também. A terceira dica é bloquear dependências baseadas em git. Com o NPM, uma dependência pode
00:03:55na verdade ser declarada como uma URL git, que ignora o registro e pode até enviar seu próprio .npmrc que
00:04:01reabilita scripts de ciclo de vida. Este é na verdade um dos truques usados no recente ataque à cadeia de suprimentos do NPM
00:04:05que atingiu o TanStack. Você pode impedir isso definindo "allow-git" como "none" na sua configuração do NPM,
00:04:10o que os bloqueia completamente, e a outra opção é definir isso como "root", o que permite que dependências baseadas em git
00:04:15sejam instaladas, mas apenas se forem declaradas no seu package.json raiz, então provavelmente
00:04:19definidas explicitamente por você. Para o PNPM, esta opção é "block-exotic-sub-dependencies". Quando isso é definido como true,
00:04:25apenas dependências diretas, ou seja, aquelas que você listou no seu package.json raiz, podem usar fontes exóticas
00:04:29como repositórios git ou URLs de arquivos diretos. Esta opção ainda não existe no Bun, mas há
00:04:35um PR aberto para adicioná-la, então talvez a veremos em breve. Como bônus para encerrar as dicas que envolvem mudanças de configuração,
00:04:40o PNPM na verdade tem uma configuração de "trust-policy", que podemos definir como "no-downgrade", e isso significa
00:04:45que o PNPM falhará se o nível de confiança de um pacote tiver diminuído em comparação com sua versão anterior. Então, se um
00:04:50pacote foi publicado anteriormente por um editor confiável, mas agora ele só tem "provenance" ou
00:04:55nenhuma evidência de confiança, a instalação falhará. Isso deve ajudar a detectar aqueles ataques que encontram maneiras de
00:05:00ignorar os processos de publicação habituais. A dica número quatro, porém, é provavelmente a mais poderosa, que é
00:05:04usar uma ferramenta que realmente analisa os pacotes que você está instalando e pode auditá-los antes que
00:05:08eles sequer toquem sua máquina. Para isso, temos duas ferramentas poderosas e completamente gratuitas. A primeira é
00:05:14o MPQ. Você pode configurá-lo criando um alias para seus comandos normais de NPM, PNPM ou Bun,
00:05:18de modo que cada vez que você executar uma instalação, ele realmente verifique algumas coisas. Ele escaneará por vulnerabilidades conhecidas
00:05:23na base de dados da Snyk e sinalizará qualquer pacote com menos de 22 dias de existência. Ele
00:05:28detectará "typosquatting", que é quando alguém publica um pacote como "express" com dois s, esperando
00:05:32que você cometa um erro de digitação e instale aquele por engano. Ele verificará a assinatura do registro e
00:05:37a "build provenance". Ele te avisará quando um pacote tiver scripts de pré e pós-instalação, e além de tudo isso,
00:05:41ele verifica coisas básicas como a contagem de downloads, se há um README, uma licença, uma URL de repositório,
00:05:46e qual é o e-mail do mantenedor, e se esse domínio ainda está registrado. Ele faz tudo isso
00:05:51e então te dá um relatório interativo sobre seus pacotes, onde você ainda pode decidir se
00:05:55deseja instalá-lo. A segunda é o "Socket Firewall". Esta é na verdade a que eu uso,
00:05:59e novamente, você cria um alias para todos os seus gerenciadores de pacotes usuais, e este suporta
00:06:03linguagens fora do JavaScript também, como Python e Rust. Similar ao MPQ, quando você executa uma instalação com
00:06:08isso, ele verificará o "Socket" e bloqueará quaisquer pacotes maliciosos confirmados por humanos, e também te avisará
00:06:12sobre quaisquer ameaças detectadas por IA, que são aquelas que ainda não foram revisadas por humanos. Para ser sincero,
00:06:16eu escolhi o "Socket Firewall" principalmente por ser o que ouvi falar primeiro, mas também confio no "Socket" já que eles
00:06:21pegaram muitos dos pacotes maliciosos recentes, e os atacantes até fizeram uma entrevista onde disseram
00:06:25que o "Socket" detectará o malware antes mesmo que o pacote chegue à sua máquina, o que é um anúncio
00:06:30muito bom para eles, e também gosto que suporte mais do que apenas JavaScript, com "uv", "pip" e "cargo".
00:06:35Se você instalar qualquer um desses, certifique-se de limpar o cache do seu gerenciador de pacotes
00:06:38só para garantir que cada pacote instalado seja verificado pelo firewall. A dica cinco é sobre seus
00:06:42arquivos de bloqueio (lockfiles). Seus lockfiles são onde reside a URL de download real de cada pacote, e o
00:06:47problema é que praticamente ninguém revisa seus lockfiles em um PR. Então, se alguém abrir um PR no seu
00:06:51repositório, eles podem editar silenciosamente uma URL resolvida para apontar para um pacote que eles controlam, e também definir o
00:06:56hash de integridade correspondente para que nada pareça estranho. Agora, na próxima vez que você rodar uma instalação, você estará puxando
00:07:01o código do servidor do atacante. A boa notícia é que, se você estiver usando o PNPM, você não é vulnerável
00:07:05a isso. Ele não mantém aquelas fontes que podem ser trocadas, e também não instalará
00:07:09nada que esteja no lockfile, mas que não esteja declarado no seu package.json. Não encontrei nenhuma
00:07:14informação concreta sobre o BUN, porém, então ele pode ainda ser vulnerável a isso. A correção, se você não
00:07:18estiver usando o PNPM, é usar uma ferramenta chamada "lockfile-lint". Você a instala como uma dev-dependency, e ela valida
00:07:23seu lockfile, verificando se cada pacote é resolvido a partir de um host confiável, como o registro NPM. Ela verifica se
00:07:28as URLs resolvidas correspondem ao nome do pacote, e também verifica se os hashes de integridade são reais também.
00:07:32Se ela suspeitar que algo foi adulterado, ela fará a instalação falhar. A dica 6 é parar de
00:07:37usar "npm install" em CI e produção, e em vez disso usar "clean install". O comando para isso no NPM é
00:07:42apenas "npm ci", e para BUN e PNPM, você na verdade adiciona a flag "--frozen-lockfile", mas eles também têm comandos
00:07:47CI como alias que fazem a mesma coisa. O PNPM na verdade usa isso por padrão se ele detectar que
00:07:52está rodando em um ambiente de CI. O comando "clean install" instala exatamente o que está no lockfile,
00:07:57nada mais, e se o lockfile e o package.json não concordarem, ele simplesmente para e gera um erro,
00:08:01em vez de adivinhar e instalar de qualquer maneira. Portanto, isso deve impedir que um atacante consiga
00:08:05substituir uma versão. Nada disso funciona, porém, se você não estiver enviando seu lockfile para o controle de versão
00:08:09em primeiro lugar, então certifique-se de que ele esteja no controle de versão e não no seu .gitignore, e admito que quando
00:08:13comecei a aprender a programar quando criança, eu realmente achava que era para ignorar esses arquivos, então estou feliz
00:08:17que aprendi a enviá-los. Então, essas seis dicas foram principalmente sobre configuração e ferramentas, mas também há alguns
00:08:21hábitos que você pode adotar para te ajudar a evitar ataques. O primeiro é parar de atualizar cegamente
00:08:25tudo. Você pode ter executado "npm update" ou as outras versões desse comando antes, e apenas
00:08:30atualizado todas as dependências para a versão mais recente de uma só vez, mas esse é o tipo de comportamento exato que esses
00:08:35atacantes esperam, então analise essas atualizações e pergunte-se por que você precisa
00:08:39atualizar. O segundo hábito está se tornando cada vez mais relevante: use menos pacotes. Cada
00:08:43dependência que você adiciona é mais uma superfície de ataque, e a maioria desses ataques se espalha através de dependências
00:08:48de uma dependência, então vale genuinamente a pena perguntar por que você precisa daquela biblioteca. Alguns exemplos comuns que vejo
00:08:53disso são coisas como "Lodash" para funções que podem ser feitas com um pequeno trecho de código, ou "Axios" quando
00:08:58"fetch" pode fazer a mesma coisa. A razão pela qual digo que isso está se tornando mais relevante é que na era da
00:09:03codificação por agentes, é bem fácil conseguir que a IA escreva algumas funções para você em vez de usar uma dependência.
00:09:08O terceiro hábito é fixar dependências em uma versão exata, para que uma atualização seja sempre uma escolha
00:09:12deliberada, mas saiba que isso na verdade apenas bloqueia os pacotes que você escolhe no seu package.json,
00:09:17e as dependências das suas dependências ainda podem usar seus próprios intervalos, que é exatamente por isso que aquele
00:09:21"cooldown" da dica 1 importa. Todos esses combinados devem te dar alguma paz de espírito de que você não
00:09:25instalará acidentalmente um pacote comprometido. Eles não são invencíveis, mas são muito melhores do que
00:09:29nada. A dica definitiva é apenas rodar tudo em um contêiner de desenvolvimento (dev container) endurecido, mas sempre achei
00:09:34que isso seja um pouco incômodo, então acabo recorrendo ao desenvolvimento local. Se você conhece alguma outra maneira
00:09:38de se proteger desse tipo de ataque, me avise nos comentários abaixo, e enquanto estiver por lá,
00:09:42inscreva-se, e como sempre, vejo você na próxima.

Key Takeaway

Aumentar a segurança da cadeia de suprimentos de software requer a configuração de uma idade mínima para pacotes, a desativação de scripts de pós-instalação e o uso de firewalls como o Socket Firewall para validar dependências antes da execução.

Highlights

  • Configurar uma idade mínima para novos pacotes no .npmrc, pnpm-config.yaml ou bunfig.toml previne a instalação imediata de pacotes maliciosos recém-lançados.

  • Desativar scripts de pós-instalação no NPM ou restringi-los no Bun e PNPM impede que pacotes maliciosos executem código arbitrário automaticamente durante a instalação.

  • Bloquear dependências baseadas em git configurando 'allow-git' como 'none' no NPM ou usando 'block-exotic-sub-dependencies' no PNPM elimina vetores de ataque que ignoram registros oficiais.

  • Ferramentas gratuitas como o Socket Firewall ou MPQ analisam pacotes e bloqueiam ameaças confirmadas antes que sejam instaladas na máquina.

  • Substituir o comando 'npm install' por 'npm ci' ou usar a flag '--frozen-lockfile' garante a instalação idêntica ao que está registrado no arquivo de bloqueio, impedindo adulterações.

  • O uso de menos dependências reduz a superfície de ataque total, especialmente ao substituir bibliotecas pesadas por funções simples escritas nativamente ou geradas por IA.

Timeline

Controle de idade e execução de scripts

  • Definir uma idade mínima para pacotes evita a instalação de ataques de cadeia de suprimentos recém-descobertos.
  • Desativar scripts de instalação automática bloqueia a execução de código malicioso durante a fase de instalação.
  • O PNPM e o BUN oferecem listas de permissões para pacotes confiáveis que exigem scripts de construção.

A maioria dos ataques à cadeia de suprimentos é identificada em poucas horas após o lançamento, tornando o atraso na instalação uma defesa eficaz. Gerenciadores como NPM, PNPM e BUN possuem configurações específicas para exigir que um pacote tenha uma idade mínima antes de ser baixado. Além disso, impedir a execução de scripts de pós-instalação é fundamental, pois essa funcionalidade, embora legítima para compilar código nativo, é frequentemente explorada para rodar malware. Ferramentas como o pacote 'Lavamote's allow-scripts' podem ser usadas no NPM para replicar a segurança de lista de permissões já nativa em outros gerenciadores.

Segurança em dependências git e lockfiles

  • Bloquear URLs git como fontes de dependência mitiga riscos de pacotes que tentam contornar registros.
  • Ferramentas como 'lockfile-lint' validam a integridade e a origem de pacotes em projetos que não utilizam o PNPM.
  • O uso de comandos 'clean install' em ambientes CI e de produção impede alterações silenciosas nas dependências.

Dependências declaradas como URLs git ignoram os registros e podem reabilitar scripts de ciclo de vida, um método usado em ataques recentes. Restringir essas dependências à raiz do arquivo package.json ou bloqueá-las completamente é uma camada de proteção adicional. A revisão de lockfiles também é essencial, já que atacantes podem editar URLs de download e hashes de integridade em PRs. O comando 'npm ci' ou equivalentes com a flag '--frozen-lockfile' forçam a instalação exata descrita no lockfile, gerando erro caso haja divergências.

Ferramentas de auditoria e bons hábitos

  • O uso de ferramentas de auditoria ativa como o Socket Firewall ou MPQ bloqueia pacotes maliciosos antes do download.
  • Evitar atualizações cegas de dependências protege contra a inclusão de versões comprometidas.
  • Reduzir o número total de dependências diminui drasticamente a superfície de ataque de um projeto.

Ferramentas de auditoria como o Socket Firewall verificam pacotes contra bancos de dados de ameaças confirmadas e heurísticas de IA, bloqueando-os antes de tocarem a máquina local. Além da tecnologia, hábitos como analisar a necessidade real de cada dependência e evitar atualizações globais em lote reduzem riscos significativos. A IA generativa auxilia na substituição de bibliotecas de utilitários pesadas por trechos de código próprios, eliminando a dependência de terceiros desnecessários.

Community Posts

No posts yet. Be the first to write about this video!

Write about this video