SnakeYaml 2.0: como resolver a vulnerabilidade de desserialização insegura
21 de junho de 2023
0 minutos de leituraEm dezembro do ano passado, informamos a você sobre a CVE-2022-1471. Esse problema de desserialização insegura poderia levar facilmente à execução de código arbitrário nas circunstâncias certas.
No artigo de aprofundamento “Vulnerabilidade de desserialização insegura no SnakeYaml (CVE-2022-1471)”, expliquei os problemas dessa biblioteca e como ela poderia ser explorada. Em resumo, por padrão, o SnakeYaml analisava o YAML recebido como um objeto genérico. Isso criava a oportunidade de desserializar outras classes disponíveis no classpath. Independentemente da ClassCastException lançada, se o objeto já tiver sido carregado, o dano está feito.
O impacto depende muito de como você usa a biblioteca. Por exemplo, muitos desenvolvedores usam YAML apenas para fornecer configurações aos aplicativos. Essa vulnerabilidade só pode ser explorada se você aceitar YAML de fontes desconhecidas, como usuários finais. Ainda assim, não podemos prever como as pessoas vão usar uma biblioteca como essa, e a configuração padrão deve ser segura.
Atualize o SnakeYaml com o Snyk Open Source
Vamos usar o Snyk Open Source para encontrar uma substituição para a antiga biblioteca SnakeYaml. Se eu executar o snyk test localmente com a CLI do Snyk, vejo que há uma substituição disponível.

A interface web também informa que uma versão do SnykYaml 2.0 está disponível para resolver o problema. O único problema é que o Spring Boot 3 ainda inclui a versão 1.x, então preciso substituir a versão manualmente no arquivo de manifesto do Maven ou do Gradle.

Atenção: alterar manualmente a biblioteca para uma nova versão principal pode causar problemas. Não faça essas alterações sem avaliar o impacto potencial no funcionamento interno do seu aplicativo.
Como mitigar a desserialização com o SnakeYaml 2.0
O SnakeYaml 2.0 foi lançado no início de 2023 para mitigar o comportamento padrão que poderia levar à execução de código arbitrário. Nessa versão, o construtor usado por todo novo yaml() agora estende SafeConstructor. Com isso, só podemos analisar um conjunto limitado de tipos. O SafeConstrutor do SnakeYaml pode construir classes Java padrão, como tipos primitivos e classes básicas, como string e map.
Agora, tipos específicos não podem mais ser analisados por padrão. Portanto, o arquivo YAML abaixo vai gerar uma exceção:
Agora, a implementação padrão não é mais vulnerável. No entanto, essa é uma alteração incompatível, então é provável que seu código atual deixe de funcionar.
Como corrigir a lógica de análise de YAML ao usar o SnakeYaml 2.x
Antes de tudo, precisamos garantir que não usamos mais o SnakeYaml 1.x. Nem mesmo a versão mais recente do Spring Boot, a 3.1, inclui atualmente o SnakeYaml 2.x. Isso significa que precisamos atualizá-lo por conta própria no arquivo de manifesto. Em projetos Maven, podemos usar a seção <dependencyManagement> do arquivo pom entre outras opções. No Gradle, também é possível atualizar dependências transitivas usando restrições de dependência.
Observe que o SnakeYaml 2.x tem alterações incompatíveis na API em relação às versões anteriores. Isso significa que precisamos reescrever a implementação de análise de YAML para usar os novos padrões seguros e voltar a fazê-la funcionar.
Vamos considerar um domínio bem simples, com duas classes:
Pessoa
Comentário
Person.java:
Comment.java:
Se você quiser criar um arquivo YAML a partir de uma entidade como a acima, provavelmente escreveu algo parecido com o código a seguir ao usar o SnakeYaml 1.x:
O resultado é o seguinte arquivo YAML:
Com o SnakeYaml 2.x, !!mypackage.Person não é mais aceito. Agora podemos eliminar a referência ao objeto ao analisá-lo para um arquivo YAML. No entanto, ainda há um problema com arquivos YAML exportados antes dessa migração.
Felizmente, ainda podemos resolver esse problema! Ao analisar um objeto específico, você pode definir qual construtor o analisador deve usar. Além disso, podemos adicionar um TagInspector específico às LoaderOptions para permitir a tag do nosso pacote. Assim, você permite apenas arquivos YAML compatíveis com o seu objeto e mantém a compatibilidade com versões anteriores dos arquivos YAML criados com as versões 1.x.
Além disso, seria melhor remover totalmente do arquivo YAML a referência ou a tag do objeto em si. Isso já era possível nas versões anteriores do SnakeYaml: bastava adicionar um representer ao objeto YAML para mapear a tag do objeto de nível superior para um mapa. Abaixo, você encontra um exemplo compatível com o SnakeYaml 2.x:
O arquivo YAML não começará mais com !!mypackage.Person (ou algo parecido). Se todos os seus arquivos YAML estiverem limpos, você poderá remover o TagInspector do analisador.
Fique por dentro das novidades da Snyk
Manter todas as versões das suas bibliotecas atualizadas é essencial para a segurança do código aberto. Usar a versão 1.x do SnakeYaml pode levar a problemas de segurança desnecessários se você aceitar direta ou indiretamente arquivos YAML de fontes externas.
Snyk Open Source ajuda você a encontrar e corrigir esses problemas ou indica uma versão alternativa, se necessário — como no exemplo a seguir, que mostra que atualizar o SnakeYaml para a versão 2.0 ou posterior elimina a vulnerabilidade de execução de código arbitrário.

Além disso, se você conectar seu repositório Git ao Snyk, podemos abrir pull requests para manter suas dependências atualizadas, mesmo quando não houver nenhum problema crítico de segurança. Prevenir é melhor do que remediar: manter suas bibliotecas atualizadas ajuda a reduzir o risco de vulnerabilidades e o trabalho extra que surge quando é preciso atualizar tudo por causa de um problema de segurança.

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.


