A frustração de reduzir a superfície de ataque em soluções open source

sexta-feira, 18 de janeiro de 2019

O desenvolvimento de softwares evoluiu muito ao longo dos últimos anos. É cada vez mais comum encontrar um cenário de desenvolvimento baseado em componentes, módulos e bibliotecas de terceiro que ajudam a resolver de forma efetiva certos problemas comuns dos projetos de software, agilizando de forma significativa os tempos de desenvolvimento.

As vantagens de utilização dos componentes são evidentes e não devem ser colocadas em dúvida, mas a realidade é que geram uma série de riscos de segurança que devem ser avaliados. O modelo de responsabilidade deve ser compartilhado em relação às vulnerabilidades e possíveis ataques, similar ao que encontramos no mundo Cloud e suas diferentes vertentes IaaS, PaaS e SaaS.

O problema principal que pode ser encontrado no cenário de desenvolvimento utilizando componentes open source começa quando alguns destes módulos utilizados em projetos de software tem falhas de segurança. De modo automático, o projeto em si se tornará vulnerável devido à esta falha. Isso não quer dizer que a vulnerabilidade pode ser explorada, mas é um risco que deve ser avaliado e, principalmente, comunicado para a organização que desenvolveu o componente.

Muitas vezes esse desenvolvimento se dá em projeto open source mantido por uma comunidade, que pode ser grande ou pequena. Não raramente, o desenvolvimento é realizado por uma ou duas pessoas que mantém as atualizações e melhorias.

Aqui está concentrara a frustração da manutenção. Manter uma biblioteca requer muito trabalho de revisão, revolução e comunicação, que não tem um retorno claro para o programador. Quando esse profissional percebe que, ainda que a biblioteca seja muito popular, a responsabilidade das atualizações não será compartilhada pela comunidade que a usa, a frustração aumenta e é aí que um cibercriminosos por encontrar um campo propício para o ataque.

Ataque
A investigação que hoje apresentamos surgiu de um ataque sofrido em setembro de 2018 pelo repositório event-stream, uma biblioteca popular que conta cm mais de 1,9 milhão de downloads semanais e que oferece funções de ajuda para o trabalho com streams em aplicações baseadas em Node.js.




Apesar da popularidade da biblioteca, sua manutenção recaía principalmente no proprietário do repositório, como pode ser percebido no gráfico abaixo de contribuições.


Resumindo o ataque, um cibercriminoso aproveitou a pouca manutenção da comunidade e convenceu o proprietário a transferir a capacidade de publicar no repositório e na plataforma NPM (Node Package Manager). Posteriormente, aproveitando essas permissões, o atacante modificou o código adicionando linhas maliciosas e publicou na NPM, conseguindo assim infectar indiretamente um volume significativo de projetos que utilizavam a biblioteca.

Existem diversos posts que explicam em detalhe como se realizou esse ataque. É uma leitura interessante que recomendamos para que você obtenha o contexto do problema e você encontra uma destas publicações aqui.

O ataque tinha um objetivo muito bem definido: o roubo de carteiras de bitcoins gerenciados pela plataforma copay-dash que usava o event-stream como uma de suas dependências, mas isso esconde o maior problema: a gestão de dependências de software e as implicações a que levam os termos de segurança dos nossos projetos, especialmente quando dependemos de bibliotecas open source.

E é esse problema que vamos analisar nessa investigação.

Hipótese
A pergunta que fizemos para a investigação foi: partindo de bibliotecas com maior número de dependência na NPM, existe algum caso em que os repositórios tenham baixa manutenção e que, por consequência, podem ter um desenvolvedor frustrado levando a um ataque como de event-stream?

Para validar essa hipótese seguimos os seguintes passos:

  1. Encontrar bibliotecas com o maior número de dependências NPM. 
  2. Definir características que definem a baixa manutenção em seus códigos. 
  3. Estudar os resultados para extrair insights e conclusões.
Investigação
Partimos das 1.00 maiores bibliotecas das quais dependem o maior número de projetos de software na plataforma NPM. Para cada uma delas extraímos usando um script Python características que permitiram determinar o nível de atividade de manutenção.

Para definir a “baixa manutenção” de código, definimos as seguintes características:

  • Os repositórios das bibliotecas que tiveram 5 commits ou menos no último ano
  • O tamanho da comunidade menor que 30 pessoas
  • Baixa porcentagem de participação da comunidade, para isso medimos a contribuição de terceiros no código fonte da biblioteca, sem levar em conta as contribuições do proprietário do repositório

Essa definição é muito restritiva e, de fato, a própria event-stream não entraria em nossa classificação já que teve 16 commits e conta com 34 contribuidores, ainda que parte desses commits tenham sido parte do ataque realizado.


Publicamos no Github o repositório: npm-attack-surface-investigation. Nele se encontra o código fonte Python que usamos para realizar a análise, caso você tenha interesse de conhece-lo.

Essa investigação foi realizada a partir do Centro TEGRA, dedicado à engenharia e desenvolvimento em cibersegurança e localizado na Galícia, Espanha. O centro é uma iniciativa conjunta da ElevenPaths, a unidade de cibersegurança da Telefônica, e do centro tecnológico galício Gradiant, com apoio do governo da Galícia. 

Resultados
Os resultados são impactantes: das 1.000 bibliotecas analisadas, 250 (25%) tem baixa manutenção, atendendo à nossa definição. Estas 250 bibliotecas acumulam cerca de 700 milhões de downloads semanais, ou seja, são projetos utilizados amplamente a nível mundial.


Destes 250 repositórios, encontramos 129 bibliotecas (12,9%) que não tiveram nenhum commit no último ano e que dispõem de mais de 330 milhões de downloads semanais.

Se juntamos a estas 129 bibliotecas que não tiveram nenhum commit no último ano àquelas marcadas como de baixa manutenção e que unicamente de commits feito pelo proprietário, o número de bibliotecas vulneráveis aumentaria para 168, somando um total de 450 milhões de downloads semanais.

Neste link você pode encontrar informações para verificar os resultados obtidos na investigação.

Conclusões
A partir dos resultados obtidos, acreditamos que nossa hipótese pode ser considerada validada e que o ataque sofrido pelo event-stream não será um caso pontual, senão uma tendência em alta para os próximos anos.

O uso de dependências externas para o desenvolvimento de software tem muitas vantagens, mas isso implica uma série de riscos que devem ser identificados e gerenciados, especialmente no nível corporativo para evitar surpresas com o surgimento de vulnerabilidades indiretas em nossos projetos, herdadas de sua árvore de dependências.

Ainda que os projetos open source tengam grande importância hoje em dia, sua manutenção é uma tarefa árdua, já que o resultado do trabalho não pode ser medido. Se unimos a isso o fato de que os projetos são abertos e que, por isso, qualquer pessoa possa compartilhar, nos damos conta de um cenário de responsabilidade distribuída, o que facilita um ataque.

Ainda que a análise que realizamos tenha de concentrado exclusivamente na NPM e no Node.js, as conclusões podem ser extrapoladas a outras linguagens de programação que se utilizam de bibliotecas open source de terceiros.

Na sequência você encontra algumas recomendações que podem apoiar você a gerencias estes riscos desde uma perspectiva clássica de segurança da informação de prevenção, detecção e resposta.

Prevenção
Desde a versão 5.x.x, a NPM gera um arquivo package.lock.json que detalha o conjunto de dependência específicas de um projeto em determinado ponto de execução. É importante utilizar esse arquivo e publica-lo junto ao código fonte do projeto, para assegurar que outros usuários tenham a mesma árvore de dependências depois de realizar um “npm install” e que não sejam impactados por patches ou “minor releaser” que tenham um potencial malicioso. Ter uma árvore clara de dependências pode ajudar a controlar os riscos a cada publicação do projeto.

Antes de incluir uma dependência externa ao seu projeto, pense se ela é realmente necessária. Em caso positivo, verifique que a biblioteca a ser utilizada tem uma comunidade ativa por trás e que haja manutenção periódica.


Detecção
Este é um capítulo com muito potencial de melhoria, há várias iniciativas que merecem ser conhecidas. Partindo da ideia de que, ao menos, devemos inventariar as dependências de nossos projetos para poder controla-las, existem ferramenta open source que facilitam a tarefa, analisando o código fonte de um projeto.

A seguir há dois exemplos que acabaram de ser apresentados pelo BBVA Labs na XII Jornada STIC do CCN-CERT em Madrid:
  • Patton: utiliza lógica difusa para encontrar vulnerabilidades públicas a partir das dependências de um projeto. 
  • Deeptracy: permite extrair todas as dependências utilizadas em um projeto. 

Resposta
Além de manter os nossos projetos de software atualizados, usar a última versão das dependências não significa mudar seque uma linha de código. É interessante contar com uma rotinha de backlog para revisar tais dependências, registrando sua versão e movendo o projeto para utilizar aquelas mais recentes.

O conceito de comunidade deve ser bidirecional, ainda que seja difícil seguir esse conceito, sempre que baseamos nossos projetos em dependências de terceiros devemos contribuir com as comunidades que gerenciam tais componentes.

Juan Elosua Tomé
Diretor da ElevenPaths no Centro I+D de Cibersegurança TEGRA da Galícia 
David Álvarez Pérez
Pesquisador em segurança da informação do centro tecnológico Gradiant.

Nenhum comentário:

Postar um comentário