pacotes de código aberto

Proteção contra pacotes maliciosos de código aberto: o que (não) funciona

Este é o terceiro episódio de uma série de artigos sobre o tipo mais comum de ataques à cadeia de fornecimento de software: aqueles que abusam de um registro público de de código aberto componentes de software. Depois de analisar no episódio anterior “Anatomia dos pacotes maliciosos: quais são as tendências?” como os malfeitores injetam comportamento malicioso em componentes publicados novos ou existentes, estamos prontos para vestir nossas jaquetas de combate a incêndios e examinar como podemos bloquear com sucesso software malicioso entregue dessa forma ou, alternativamente, lidar com um incidente cibernético potencialmente grave porque tomamos a abordagem errada.

A maioria dos profissionais conscientes da segurança tem ideias sobre como lidar com essa ameaça. Ouvimos gerentes de segurança dizendo sem hesitação que SCA as ferramentas já informam quando uma versão do pacote é malware. Ou que elas dependem de componentes de software bem conhecidos e altamente revisados, onde qualquer malware seria prontamente detectado e removido. Elas usam versões menores/patch abertas para obter automaticamente correções de vulnerabilidades, e essa é a maneira adequada e recomendada de reduzir o risco em dependências de código aberto, seguindo o “remendar cedo, remendar frequentemente”Princípio. 

Neste episódio, analisaremos porque é que estas ideias estão erradas e como tais equívocos estão a contribuir para a popularidade deste mecanismo de ataque e para o risco esmagador que as organizações enfrentam. Terminaremos com o que funciona e qual é o esforço e os recursos envolvidos.

Equívocos comuns

Durante nossa jornada com segurança de software, vimos a evolução das técnicas de ataque e uma ampla gama de ideias de pessoas preocupadas com a segurança. As organizações muitas vezes entendem mal o que funciona contra esta ameaça, por isso primeiro examinaremos o que não funciona, condensado na seguinte lista, não exaustiva, de equívocos.

Equívoco nº 1: SCA ferramentas já relatam componentes maliciosos

De fato! Mas depois do fato… Quando provavelmente é tarde demais se o elemento foi usado em uma construção de software, e os atores mal-intencionados já ganharam uma posição em um desenvolvedor ou CI/CD host. Segredos podem ter sido exfiltrados, malware adicional baixado e instalado, e talvez o adversário tenha se movido lateralmente e já tenha obtido acesso em outro lugar. 

Análise de composição de software (SCA) ferramentas foram projetadas para identificar potenciais vulnerabilidades conhecidas. Ferramentas modernas fazem um ótimo trabalho aumentando a relação sinal-ruído, determinando se a vulnerabilidade é realmente alcançável ou explorável. Mas elas são inúteis contra novos malwares. Pense em um componente malicioso como uma vulnerabilidade de dia zero: somente quando seu comportamento malicioso é detectado, o componente é relatado ao registro de retenção, que após uma revisão por uma equipe de segurança é confirmado como malicioso e removido do registro

Nesse ponto, o mundo (incluindo SCAs) sabe que instalar ou usar o componente (ou algumas versões de um componente existente) não é uma coisa boa. Mas isso é quando o componente não está disponível no registro. Saber que tenho vulnerabilidades em componentes de terceiros, ou mesmo componentes que foram categorizados como maliciosos pelo registro é bom, mas infelizmente SCA ou ferramentas comuns de auditoria não ajudam neste contexto. A menos que o SCA/ferramenta de auditoria pode realmente saber com antecedência que um componente é malicioso antes de ser usado em sua organização.

Lembre-se de que qualquer solução contra componentes maliciosos de código aberto deve detectá-los no vôo, entre o momento em que o componente é publicado no registro e o momento em que o componente (versão) é usado pela primeira vez em sua organização. E isso inclui componentes transitivos.  

Equívoco nº 2: controlar os scripts de instalação no momento da construção evita comportamento malicioso de componentes de código aberto

Vários gestores de pacotes oferecem a capacidade de executar scripts (incluídos no componente tarball ), por motivos legítimos, como compilar itens necessários em diferentes plataformas, gerar código ou executar testes, e todos devemos saber que eles podem ser abusados ​​por malfeitores se scripts maliciosos forem incluídos no tarball ou se o invasor puder fazer um ataque malicioso script executado em vez do bom.

Sabendo disso, podemos configurar o gerenciador de pacotes para ignorar scripts. Por exemplo, com o NPM o –Ignore-scripts sinalizador (ou uma propriedade de configuração no .npmrc arquivo) ignora os scripts durante a instalação. Isso pode produzir alguns problemas porque a execução de scripts é comum em muitos ecossistemas: Alguns gerenciadores de pacotes nem mesmo permitem desabilitar a execução de scripts (dica: prompt “Quais gerenciadores de pacotes não permitem desabilitar a execução de scripts de instalação?”em sua IA favorita). Mas isso não protege em geral (precisamos garantir que a configuração de ignorar desabilitação esteja em todo lugar). 

E quando o comportamento malicioso não está localizado nos scripts de instalação, mas no software a ser executado em tempo de execução, esta opção por si só não nos protege. 

Equívoco nº 3: a fixação de versão impede a instalação de componentes maliciosos

Há uma compensação entre corrigir antecipadamente e muitas vezes com versões abertas (permitindo que o gerenciador de pacotes instale automaticamente novas atualizações quando disponíveis para correções de segurança) e fixação de versão (tendo todas as dependências diretas e transitivas de um software em versão fixa). Os princípios de segurança são teimosos e às vezes contraditórios, como acontece com “atualizar antecipadamente, corrigir frequentemente” e “a atualização não deve ser tomada de ânimo leve”. Alguns gerenciadores de pacotes fazem atualizações automáticas com intervalos de servidores da maneira recomendada. Ótimo se você também deseja receber atualizações maliciosas! Sim, os componentes devem ser atualizados para receber correções de segurança que eliminem as vulnerabilidades o mais rápido possível, mas… nunca deixe o gerenciador de pacotes fazer isso automaticamente.

Equívoco nº 4: Usar componentes confiáveis ​​é seguro. Qualquer versão maliciosa seria prontamente encontrada, divulgada e removida.

Por que um componente é confiável? Possivelmente porque é altamente popular, com muitos olhos procurando por vulnerabilidades, um grande número de colaboradores para manutenção, com vários mantenedores principais que revisam diligentemente todos pull requests. A realidade é bem diferente. Alguns componentes essenciais são mantidos por um único desenvolvedor não remunerado. Frameworks amplamente utilizados têm alguns colaboradores regulares, com um número rapidamente decrescente de commits por mantenedor (projetos populares têm uma longa cauda de contribuidores que realizam algumas tarefas commit e nunca mais volte). E há muitos projetos populares com um único mantenedor.

Imagine-se dizendo “Ah, estamos usando imagens Spring Boot/Angular/React/PyTorch/base oficial do Docker, então o risco de que você está falando é muito baixo.” Talvez isso seja verdade, nós, fornecedores de segurança, espalhamos o medo o tempo todo e interferir nas equipes de desenvolvimento para mitigar um risco discutível é um absurdo. Você pode ficar tentado a pular para o parágrafo de aceitação de riscos (na próxima seção) e pronto. Infelizmente, os componentes mais populares são alvos de maus atores e, por exemplo, o popular Biblioteca PyTorch foi atacada no passado.

“Prontamente encontrado, divulgado e removido”.  Leva dias para que um novo componente malicioso seja removido do registro público. Os registros são cautelosos ao remover uma versão do componente, para sempre. Nossa experiência é que, uma vez relatado por nossa parte, o tempo médio para o registro remover a versão afetada é de 39 horas, mais de um dia e meio. Existem componentes maliciosos que aparecem uma semana após nosso relatório inicial no registro antes de serem removidos. E, em alguns casos, o componente é removido somente depois que uma vítima ou uma empresa de resposta a incidentes relata um incidente envolvendo o componente. 

O que NÃO funciona contra componentes maliciosos

Qualquer abordagem inespecífica falhará miseravelmente. Isto é uma certeza, você não está fornecendo contramedidas eficazes para o risco associado a esta ameaça. 

Tradicional SCA ferramentas informam sobre malware conhecido, mas têm uma grande janela de exposição. A menos que estejam realizando proativamente a detecção de malware com bloqueio forçado de componentes maliciosos, elas não funcionam contra essa ameaça. 

Desabilitar scripts de instalação pode ajudar, mas precisa ser aplicado em todos os lugares onde um componente precisa ser instalado. O mesmo acontece com a fixação de versão, pois as versões não podem ser fixadas a partir de um estado inicial seguro para sempre.

Presumir que componentes populares recebam atenção suficiente para que não possam ser injetados com comportamento não intencional em um ataque à cadeia de suprimentos sem uma detecção quase instantânea para evitar qualquer dano é ingênuo e arriscado. Você não quer viver no limite, quer?

Se você parar neste ponto, então aceitação de risco é a única coisa que você pode fazer: Esta é uma decisíon que precisa ser documentado em seu modelo de ameaça/avaliação de risco, incluindo a justificativa para aceitar o risco e suas potenciais implicações. Aumente a conscientização comunicando-a à gerência e outras partes relevantes. Alguns contingência pode ser planejado quando um componente malicioso é instalado ou incluído no seu software, mas isso é difícil porque os invasores têm muitos caminhos a seguir. Os detalhes de um ataque à cadeia de abastecimento baseado na utilização de um componente malicioso alterarão drasticamente a divulgação pública do incidente, o que provavelmente é obrigatório ao abrigo do quadro regulamentar da sua organização. Você também pode abordar controles de compensação or risco de transferência por exemplo, com seguro.

No entanto, existem controles que abordam a ameaça e devem ser considerados se você não estiver satisfeito com a aceitação do risco. Por favor, continue lendo.

O que funciona contra ataques que usam componentes maliciosos

Manipulação de versão sólida

A fixação de versão com alterações de versão controladas e informadas é o caminho a seguir, para equilibrar a necessidade de remover vulnerabilidades sem receber malware. Mas lembre-se do equívoco nº 3: a fixação de versão por si só não é suficiente para bloquear códigos maliciosos provenientes de novas versões, porque no futuro você precisará atualizar versões em qualquer dependência direta ou indireta. Nesse momento você precisa de evidências fortes o suficiente de que todas as versões modificadas não contêm malware.

Aviso Antecipado

Uma abordagem para o problema dos componentes maliciosos é um sistema de alerta precoce (denominado aqui como Alerta antecipado de malware ou MEW), onde novas versões publicadas (para componentes novos ou existentes) são analisadas por um mecanismo de detecção, que quando forem encontradas evidências suficientes pode classificar a nova versão como potencialmente maliciosa. 

A automação é essencial aqui, pois é impossível revisar manualmente todos os novos componentes na taxa de publicação atual. Portanto, o mecanismo de detecção precisa combinar uma variedade de técnicas, talvez incluindo análise estática, dinâmica e de capacidade, reputação do usuário e evidências provenientes de discrepâncias entre os metadados do componente e o conteúdo do tarball, ou entre o tarball e o repositório de origem onde o componente supostamente está localizado. vem de.

Há um zona escura entre o horário de publicação e o momento em que o mecanismo analisa o conteúdo do componente, mas não deve ultrapassar alguns minutos. O esquema pode ser modificado, por exemplo, aguardando a análise de novos componentes antes de permitir que sejam instalados e usados ​​na construção do software. pipelines ou analise-os sob demanda quando necessário. Um componente em uma determinada versão é imutável  , portanto, ele precisa ser analisado apenas uma vez.

A automação total não é possível e é necessária uma análise de segurança para componentes potencialmente maliciosos. Cuidado com os proponentes da panaceia digital: a IA e o aprendizado de máquina não estão desenvolvidos o suficiente para dar a última palavra quando se trata de confirmar se um componente suspeito contém malware. Claro, o aprendizado de máquina desempenha um papel fundamental no mecanismo de detecção na classificação do componente de entrada a partir das evidências brutas capturadas, mas uma vez que o componente é “colocado em quarentena”, a palavra final recai sobre a revisão manual por uma equipe de segurança com experiência em componentes maliciosos. Isso confirma qualquer malware potencial ou o reclassifica como seguro. E o período de tempo está no intervalo de horas. 

O registro informa sobre a versão/componente malicioso; o registro então realiza sua análise para confirmar e procede à divulgação pública e remoção do registro. Alguns registros mantêm um pacote de retenção de títulos. O intervalo de tempo aqui são os dias ou semanas desde a publicação, que é o 'tempo de permanência'ou'janela de exposição' para a maioria dos componentes maliciosos.

É possível saber se a versão de um componente é maliciosa?

Portanto, para um alerta antecipado, precisamos dar uma resposta satisfatória a esta pergunta: Como posso saber se uma biblioteca ou pacote (não) é malicioso? Como reunir evidências suficientes de comportamento malicioso? Possível, mas difícil, pois os adversários usam muita engenhosidade para evitar a detecção. Existem diferentes abordagens, cada uma com prós e contras.

Análise estática pode examinar todos os caminhos de execução, verificar técnicas usadas pelos invasores sem executar o componente e executar tarefas de pré-processamento, como desofuscação ou decifração. À medida que os invasores tentam esconder suas travessuras, as tentativas de ofuscação são de fato evidências de malware (mas observe que os componentes legítimos ofuscam o código para preservar a propriedade intelectual, contradizendo “open source”). Apenas uma minoria de ataques altamente sofisticados com forte ofuscação precisa de sandbox, mas essa forte ofuscação é um sinal revelador de malícia. Observe que os ataques convencionais SAST As ferramentas foram projetadas para vulnerabilidades não intencionais, não para intenções maliciosas, como backdoors.

Análise dinâmica executa o componente e examina a resposta instrumentando o tempo de execução, normalmente fornecendo um ambiente em área restrita. O comportamento malicioso desencadeado sob certas condições pode passar despercebido: observe que o malware pode usar técnicas de evasão como Evasão de Virtualização/Sandbox para ativar somente quando não estiver sob escrutínio e também um sinal revelador de atividade maliciosa para qualquer mecanismo de análise estática.

Análise de capacidades considera o que o componente faz: onde ele se conecta, quais arquivos ele acessa, quais comandos ou programas são executados, a E/S do terminal ou dispositivo executada ou quais chamadas de sistema são invocadas. Essa impressão digital do comportamento pode ser comparada (para um componente existente) entre versões, portanto, quando um comportamento inesperado for detectado, essa evidência poderá levantar suspeitas de possíveis atividades maliciosas injetadas na nova versão. Essa abordagem segue as etapas de triagem que os analistas de segurança seguem quando enfrentam malware em potencial: uma inspeção usando cordas ou ferramentas semelhantes. Essa abordagem detecta comportamento malicioso independentemente das condições de acionamento e funciona quando nenhum código-fonte está disponível.

Análise de contexto coleta informações sobre como o componente foi publicado e por quem. As campanhas de maus atores geralmente usam novas contas de usuário que não estão sujeitas a nenhum processo de verificação rigoroso. O rastreamento de atividades anteriores pode fornecer insights sobre o usuário subjacente, principalmente em busca de anomalias que possam sugerir um possível comprometimento. A reputação é tão difícil de ganhar e tão fácil de perder! Um usuário sem atividade passada é neutro, mas o carma persegue o malévolo. Hacktivistas ou usuários normais que tiveram suas credenciais de publicação roubadas devem ser monitorados cuidadosamente.

Outra informação contextual é qualquer discrepância entre o repositório de origem supostamente usado para criar o tarball do componente e o conteúdo do próprio tarball. E também seguir boas práticas, como criar tags ou releases no repositório fonte correspondentes às versões do componente publicadas no registro público. Quando o repositório de origem em um determinado commit está marcado com release e, de repente, uma versão falha em segui-lo, o que por si só é uma forte evidência de que o componente pode estar contaminado: o malfeitor pode ter comprometido a conta usada para publicar o componente, mas não tem permissões de gravação no código-fonte repositório). Muitos ataques são detectados rotineiramente usando estas regras: por exemplo, o Ataque de livro-razão poderia ser facilmente detectado ao longo destas linhas. A análise de contexto, portanto, identifica tais anomalias no processo de publicação.

Firewall de Dependência

Uma abordagem diferente é ter uma lista de permissões abrangente de componentes para todos os gráficos de dependência usados ​​em seu software, portanto, em qualquer compilação pipeline executado em sua organização, apenas versões de componentes aprovadas podem ser instaladas e usadas. O "firewall”é aplicado usando um registro interno onde os tarballs para as versões de componentes permitidas são servidos (em cache ou em proxy). Observe que qualquer lista de permissões não funcionará, a menos que você tenha a tecnologia para classificar qualquer nova versão como razoavelmente segura, para que possa ser adicionada à lista de permissões. 

Observe que o aviso antecipado (detecção rápida o mais rápido possível após a publicação da nova versão) precisa ser combinado com alguma forma de usar essas informações proativamente para bloquear o componente que afeta a compilação pipelines ou as máquinas dos desenvolvedores  . Chamamos isso de “firewall de dependência”: um mecanismo de quarentena para proteger compilações automatizadas de pacotes maliciosos. Pacotes internos e registros de imagens são bons para isolar as organizações do mal externo, mas são necessárias evidências suficientemente fortes para tornar a quarentena eficaz. 

Sandbox de tempo de execução

Uma abordagem alternativa para detecção em tempo de publicação é analisar o comportamento em tempo de execução. A ideia é capturar o comportamento esperado do software e detectar (ou bloquear) quaisquer anomalias encontradas. Essa linha de ação tem o problema de ter que instrumentar o tempo de execução para monitoramento ou bloqueio, e é uma ideia promissora que será agregada ao arsenal de mecanismos de proteção contra a praga de componentes maliciosos.

Definindo uma estratégia abrangente

A estratégia recomendada precisa combinar diferentes técnicas no processo de desenvolvimento de software, assumindo o controle das atualizações de versão para bloquear a entrada de componentes maliciosos. Devemos acomodar a fixação de versões para evitar infecção automática com atualizações de versões para obter correções para as vulnerabilidades importantes; uma avaliação rápida e eficiente das dependências diretas e indiretas durante as atualizações de versão para ter evidências suficientes de que não estão infestadas de malware. As compilações de software que dependem de componentes maliciosos conhecidos devem ser bloqueadas. E tudo deve ser aplicado.

Use a fixação de versão, quando possível, pois isso torna as compilações mais reproduzíveis. Fixação de versão com alterações de versão controladas e aprovadas manualmente e assistido por tecnologia auxiliar, deve avaliar se a atualização traz malware ou quebra o software e conciliar a atualização para corrigir vulnerabilidades com evitar infecção por malware. As ferramentas podem ajudar aqui, (1) priorizando quais vulnerabilidades realmente importam (alcançáveis ​​e exploráveis, com alto risco de serem alvo de invasores), (2) selecionando as versões alvo que são compatíveis com os usos atuais dos componentes e não quebram o software, (3) escolher versões de destino que não contenham comportamento malicioso e (4) tornar a atualização de versão para dependências diretas e indiretas muito rápida, sugerindo alterações nos arquivos de manifesto que poderiam ser aprovadas rapidamente. A etapa (3) precisa de informações específicas sobre componentes maliciosos o mais próximo possível do momento de sua publicação.

Este processo de atualização de dependências deve ser Forçado e verificado em todos os lugares. O processo deve ser documentado, e todas as partes envolvidas devem ser treinadas, pois frequentemente o desenvolvimento e a construção/implantação do software são externalizados. CI/CD pipelines devem ser modificados adequadamente, para que a automação não permita que uma dependência indireta maliciosa entre na compilação: guardrails bloquear a compilação se houver evidências suficientes de malware em potencial em uma dependência é o caminho recomendado. 

Se sua organização tiver um registro interno que atue como proxy de segurança para manter as versões de componentes permitidas, você deverá obter informações sobre componentes maliciosos (além de outros critérios) para verificar um componente solicitado antes de adicioná-lo à lista de permissões. 

Consumir software de código aberto com segurança não é fácil, e o fator malware deve ser totalmente levado em consideração, com esforço semelhante colocado no tratamento de vulnerabilidades.

Uma nota final: Proveniência de origem, na forma de atestados de software, gerados no momento da construção do componente, é outra peça-chave no esforço para rastrear o artefato (tarball do componente) com as fontes e o processo de construção que o produziu. Observe que esse link entre o snapshot de origem + ambiente de compilação e o artefato de software associado (assinado pelo sistema de compilação confiável) não impede, por si só, que o componente não contenha comportamento malicioso, mas torna mais difícil para os bandidos injetarem malware . E tornar a validação de proveniência um requisito comum para o consumo de componentes de código aberto levará muito tempo, e apenas adicionado recentemente ao NPM. Tornar esses sistemas confiáveis ​​de construção e implantação à prova de adulteração ou permitir a detecção de qualquer violação na construção é uma história diferente, fora do escopo desta postagem. 

Outras leituras

o próximo episódio Pacotes maliciosos de código aberto: a abordagem Xygeni apresentaremos a estratégia que seguimos na Xygeni para nossos Alerta antecipado de malware (MEW). Novas versões de pacotes nos registros públicos de pacotes e imagens são digitalizadas e as evidências são obtidas usando uma combinação de análises estáticas, dinâmicas, de recursos e contextuais. A evidência, combinada com a reputação do usuário e o histórico de alterações nos repositórios de código-fonte, permite uma classificação totalmente automatizada de um componente em categorias de alto risco e provavelmente maliciosas. O sistema aprende com evidências anteriores coletadas em pacotes para reduzir ao mínimo os falsos positivos. 

As organizações inscritas recebem uma notificação de aviso sobre os componentes que estão usando, direta ou indiretamente, quando uma versão maliciosa é categorizada. Em seguida é feita uma análise manual pelos nossos analistas, que confirma ou rejeita a classificação. Para malware confirmado, o registro público é notificado para que possa realizar sua própria análise e normalmente remover a versão maliciosa ou tomar medidas adicionais, como bloquear ou remover a conta do usuário em questão.

Explicaremos como estamos ajudando NPM, PyPI, GitHub e outras infraestruturas importantes no ecossistema de código aberto a reduzir o tempo de permanência de um novo componente malicioso publicado que permanece ativo até que seja confirmado como malware e removido do registro. E como as organizações podem se beneficiar do sistema MEW para ter uma proteção muito melhor contra ataques à cadeia de fornecimento de software envolvendo componentes de código aberto.

  • De qualquer forma, os usuários do componente precisam verificar se o tarball do componente está armazenado em cache ou registrado em algum lugar, por exemplo em um registro interno, para que a doença seja erradicada.
  • O componente empacotado inclui um manifesto que declara seu conteúdo e metadados, código fonte ou compilado, scripts de instalação e itens adicionais, como suítes de testes, de acordo com um formato de pacote e normalmente em formato compactado. Isso é chamado de “tarball de componente”.
  • Mesmo que o agente mal-intencionado possa modificar um componente publicado devido a uma violação no próprio registro, um resumo criptográfico simples pode detectar qualquer alteração no tarball após a conclusão da análise.
  • Lembre-se de que alguns componentes maliciosos são executados no momento da instalação, portanto, podem afetar os nós do desenvolvedor que inadvertidamente executam “npm install X” com X como um componente malicioso.  

Pacotes maliciosos de código aberto: o problema

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