Como lidar com vulnerabilidades de segurança no Spring Boot
29 de novembro de 2023
0 minutos de leituraNo desenvolvimento de software, gerenciar dependências é uma parte essencial da criação de aplicações robustas e seguras. O Spring Boot, muito usado por desenvolvedores Java, facilita a criação de aplicações, mas há mais do que parece à primeira vista. Manter as dependências sob controle é fundamental para garantir que seus projetos Spring Boot funcionem sem problemas e continuem resilientes diante de ameaças em constante evolução.
Um aspecto fundamental do gerenciamento de dependências no Spring Boot é a segurança. Vulnerabilidades de software são descobertas com frequência. Manter as dependências do seu projeto atualizadas é como vestir uma armadura de segurança digital. Dependências desatualizadas podem ser como portas destrancadas, convidando possíveis ameaças a entrar — e queremos evitar isso.
Como encontrar vulnerabilidades no Spring Boot
As ferramentas de análise de composição de software (SCA) são muito úteis para desenvolvedores. Elas oferecem uma solução simples para gerenciar dependências, lidar com vulnerabilidades de segurança, navegar por questões de licenciamento e garantir a conformidade dos seus projetos de software. Ao usar Snyk Open Source como sua ferramenta de SCA, você pode descobrir facilmente se os pacotes do seu Spring Boot contêm vulnerabilidades.
No meu projeto de exemplo, encontrei várias vulnerabilidades. A primeira é um problema de segurança de alta severidade em `netty-codec-http2`. Essa é uma dependência transitiva trazida por `spring-boot-start-webflux`, como você pode ver abaixo.

A segunda vulnerabilidade que quero abordar é um problema de execução arbitrária de código de severidade média, introduzido pelo pacote `snakeyaml`. Essa também é uma dependência transitiva, desta vez trazida por `spring-boot-starter-security`.

Hoje, não vou entrar nos detalhes de cada vulnerabilidade, mas você pode conferir o artigo dedicado para saber mais sobre o problema do `snakeyaml`. Vamos nos concentrar em resolver o problema e implementar a melhor solução.
Como corrigir pacotes vulneráveis na sua aplicação Spring Boot
Para a primeira vulnerabilidade, há uma correção bem definida. Minha aplicação é baseada no Spring Boot 2.7.16 e, portanto, o `spring-boot-starter-webflux` também está na versão 2.7.16.
Atualizar o starter Webflux para a versão 2.7.17 deve resolver o problema. Há várias maneiras
de fazer isso, mas nem todas são recomendadas.
Normalmente, o manifesto do seu Spring Boot é parecido com o código a seguir:
Maven:
Gradle:
Atualize o starter do Spring Boot
O número de versão de cada `spring-boot-starters` é definido pelo `spring-boot-starter-parent` (Maven) ou pelo plugin `org.springframework.boot` no Gradle.
Isso acontece principalmente porque todos esses pacotes starter fazem parte da mesma versão do Spring e são testados em conjunto.
Ao analisar a primeira vulnerabilidade encontrada no meu projeto, a sugestão de correção é atualizar `spring-boot-starter-webflux` para a versão 2.7.17, resolvendo a vulnerabilidade de segurança de alta severidade. Isso sugere que basta corrigir o pacote Webflux, especificando uma versão, como no exemplo abaixo.
Maven:
Gradle:
Mas pare por aqui! Essa não é a maneira recomendada de resolver o problema. A versão específica 2.7.17 é usada no lugar da versão definida pelo parent. Embora isso possa funcionar por se tratar de uma versão de patch, não é a solução mais adequada nem a mais segura. Como o semver não garante que as APIs permaneçam intactas, não podemos ter certeza de que isso vai funcionar. Mas o argumento mais importante é que provavelmente já existe uma nova versão completa do Spring Boot.
Lembra que eu disse que esses starters precisam funcionar em conjunto? Por isso, a melhor opção é atualizar toda a distribuição do Spring Boot para a versão 2.7.17. Isso é ainda mais importante ao atualizar para versões minor ou major de um pacote, que podem causar incompatibilidades na API e impedir que os componentes funcionem bem juntos. Então, neste exemplo, atualize o parent (Maven) ou o plugin (Gradle), em vez dos starters individualmente.
Maven:
Gradle:
Recomendo que você vá além e atualize toda a versão do Spring Boot para a versão mais recente compatível. Para descobrir qual é, basta acessar https://start.spring.io.

Atualização de dependências transitivas
No segundo caso, o Snyk identificou que não há uma recomendação clara de correção na minha aplicação. No momento, também não há uma versão disponível de um `spring-boot-starter` sem essa dependência transitiva insegura. O que sabemos é que existe uma versão atualizada da dependência transitiva. Atualizar para o `snakeyaml` 2.0 vai resolver o problema.
Mais uma vez, vale ressaltar que este é apenas um exemplo. Talvez já exista uma versão atualizada de um `spring-boot-starter` quando você ler este artigo, então não deixe de confirmar. Para saber mais sobre a vulnerabilidade do SnakeYaml, confira nosso artigo dedicado sobre o assunto.
Atualização do parâmetro de versão
Primeiro, verifique se a versão do pacote que você quer atualizar é uma propriedade do Spring Boot. A documentação do Spring Boot inclui um apêndice com as versões das dependências de cada versão específica. Você também encontra lá as propriedades de versão. Essas propriedades podem ser sobrescritas no Maven e no Gradle para usar uma versão mais recente da dependência transitiva.
No Maven, você pode adicionar uma propriedade à seção de propriedades.
No Gradle, podemos editar essa propriedade em um arquivo `gradle.properties`:
Essa é a opção preferida em relação ao gerenciamento de dependências, pois `snakeyaml` é apenas uma biblioteca. No entanto, em muitos casos, há mais de uma biblioteca. A versão pode se referir a um BOM (bill of materials), que não deve ser confundido com um SBOM. Um BOM representa um conjunto de grupos de pacotes que precisam ser usados em conjunto e, essencialmente, ter a mesma versão — como um pacote de API e outro de implementação. Ambos precisam estar na mesma versão para funcionar como esperado.
Declaração de gerenciamento de dependências
Outra opção é usar os mecanismos da sua ferramenta de build para atualizar dependências transitivas. Essa alternativa só deve ser usada se você não puder atualizar a propriedade de versão conforme mostrado na seção anterior.
No Maven, isso costuma ser adicionado ao bloco `dependencyManagement`. Esse bloco garante que a versão atualizada indicada nele seja usada sempre que a biblioteca for incluída como dependência transitiva.
Maven:
Como usamos o plugin dependency-management do Spring no nosso arquivo Gradle, temos recursos bem semelhantes disponíveis para o Gradle. Esse plugin foi inserido pelo inicializador do Spring Boot ao gerar a estrutura inicial do meu projeto.
Gradle:
Se você não usa o plugin `io.spring.dependency-management`, também pode adicionar constraints a dependências transitivas no Gradle para atualizar uma dependência como a do exemplo abaixo. Lembre-se de que essas constraints não funcionam bem com o plugin `dependency-management` do Spring. Portanto, você deve usar um ou outro.
Analise suas aplicações Spring Boot com o Snyk
Analisar sua aplicação Spring Boot com o Snyk é essencial para garantir a segurança e a estabilidade do seu software. O Snyk ajuda a identificar vulnerabilidades nas dependências da sua aplicação, que agentes mal-intencionados podem explorar se não forem corrigidas. Depois de ler este artigo, você também já sabe qual é a melhor maneira de aplicar as recomendações de correção fornecidas pelo Snyk.
Analisar sua base de código regularmente ajuda a tratar problemas de segurança de forma proativa e reduz o risco de vazamentos de dados e outros incidentes de segurança. Por isso, inclua as análises no seu fluxo de trabalho e saiba como agir quando uma vulnerabilidade aparecer.
Abaixo, analisei minha aplicação com o Snyk CLI antes e depois da correção. Optei por atualizar a versão geral do Spring Boot e a propriedade de versão específica do `snakeyaml`.
Antes:

Depois:

Então, lembre-se: quando encontrar no Snyk uma vulnerabilidade relacionada a uma dependência da sua aplicação Spring Boot, siga estas etapas:
Atualize a versão geral do Spring Boot em vez de atualizar um starter específico.
Ao atualizar a versão do Spring Boot, não basta atualizar as propriedades de versão das dependências do Spring Boot.
Use o gerenciamento de dependências no Maven ou no Gradle para atualizar dependências transitivas específicas.
Comece a resolver desafios de capture the flag
Aprenda a resolver desafios de capture the flag assistindo sob demanda ao nosso workshop virtual introdutório.



