Segurança em JSON: vulnerabilidades comuns e como evitá-las
O JSON não tem código executável e escapa dos riscos de entidade externa do XML e das surpresas de coerção de tipos do YAML, por isso tem fama de ser seguro de analisar. A etapa de análise merece quase toda essa fama. As vulnerabilidades reais estão no que seu código faz com o objeto analisado depois.
Prototype pollution via entrada JSON
Objetos JavaScript herdam de uma cadeia de protótipos compartilhada. Se um JSON não confiável contém uma chave como "__proto__" e seu código faz o merge dele num objeto existente sem proteger as chaves especiais, um atacante pode injetar propriedades no próprio Object.prototype. Isso afeta todo objeto da sua aplicação, não só aquele que recebeu o merge.
{
"__proto__": {
"isAdmin": true
}
}Faça deep-merge disso num objeto de usuário com um merge recursivo que não trata à parte as chaves __proto__, constructor ou prototype, e todo objeto do processo, incluindo os que nunca tocaram esse payload, pode ganhar uma propriedade isAdmin com valor true. Atacantes já exploraram essa classe de vulnerabilidade em várias bibliotecas npm populares de merge/extend.
Como evitar prototype pollution
Use Object.create(null) para mapas construídos a partir de chaves não confiáveis, pois ele não tem protótipo para poluir. Prefira Map a objetos simples quando as chaves vêm de entrada do usuário e você não precisa serializar o resultado em JSON. Se você precisar fazer deep-merge de JSON não confiável num objeto existente, use uma utilidade de merge que bloqueie __proto__, constructor e prototype como chaves, e verifique se sua dependência já corrigiu isso (a maioria das bibliotecas principais corrigiu nas versões recentes) em vez de presumir. Mantenha as dependências em dia: os mantenedores corrigiram essa classe de vulnerabilidade muitas vezes em pacotes populares, à medida que pesquisadores encontravam novas formas de contornar as correções.
Desserialização insegura além do JSON.parse puro
O JSON.parse() puro produz dados simples: strings, números, booleanos, null, objetos simples e arrays. Ele não consegue construir instâncias de classes arbitrárias nem executar código, ao contrário de alguns outros formatos de serialização (o pickle do Python pode executar código arbitrário na desserialização). O risco aparece quando uma função reviver ou uma etapa posterior reconstrói instâncias de classes ou executa lógica com base em valores de campos não confiáveis. Um exemplo: código que lê um campo "type" do JSON e o usa para fazer require() de um módulo ou despachar para um handler por nome sem conferir a string contra uma allowlist.
Valide contra um schema antes de confiar em JSON não confiável
JSON.parse() garante validade sintática e nada sobre se os dados correspondem ao formato que seu código espera. Um corpo de requisição que é JSON válido mas está sem um campo obrigatório, ou traz uma string onde você esperava um número, pode derrubar código downstream ou produzir comportamento errado sem nenhum erro. Valide o JSON de entrada contra um schema (JSON Schema, Zod, Joi ou similar) antes de usá-lo. Você captura estrutura malformada na fronteira, rejeita com uma mensagem de erro útil em vez de um crash confuso três funções adiante, e o schema documenta o formato que o endpoint espera.
Um checklist prático
Valide JSON não confiável contra um schema na fronteira, antes que ele alcance a lógica de negócio. Não faça deep-merge de JSON não confiável em objetos de longa duração sem uma utilidade de merge que bloqueie chaves perigosas. Evite funções reviver ou dispatch dinâmico baseado em campos de string não confiáveis, a menos que você confira os valores contra uma allowlist. Mantenha atualizadas as dependências que manipulam JSON (parsers, utilidades de merge, validadores de schema), porque pesquisadores continuam achando novas variantes desses bugs. Defina limites de tamanho para corpos de requisição JSON, para reduzir a exposição a ataques de exaustão de recursos via payloads enormes ou muito aninhados.
FAQ
- O JSON.parse() em si é vulnerável a execução de código, como o eval()?
- Não. JSON.parse() só produz estruturas de dados simples (strings, números, booleanos, null, objetos simples, arrays) e nunca executa código, ao contrário da análise de JSON via eval() que alguns codebases muito antigos usavam antes de o JSON.parse() nativo se tornar padrão. O JSON.parse() moderno é seguro quanto a execução de código; os riscos discutidos aqui vivem no que seu código faz com o resultado analisado depois.
- O é prototype pollution em termos simples?
- Um atacante envia uma entrada (muitas vezes JSON com uma chave __proto__), e código que não protege nomes de propriedade especiais faz o merge dela num objeto. O atacante pode então adicionar ou sobrescrever propriedades no objeto base compartilhado do qual todos os objetos JavaScript herdam, o que afeta a aplicação inteira.
- Preciso de validação de schema se já uso TypeScript?
- Sim. O compilador do TypeScript apaga os tipos, então eles não oferecem proteção nenhuma em tempo de execução. Nada verifica um payload JSON malformado ou malicioso que chega via HTTP, a menos que você o valide com uma biblioteca como Zod, Joi ou um validador de JSON Schema. O TypeScript impede que você escreva código que trate mal o formato esperado; ele não consegue verificar se os dados que chegam correspondem a esse formato.
- YAML ou XML são mais seguros que JSON para analisar?
- Não, eles têm suas próprias classes de vulnerabilidade. Parsers YAML em algumas linguagens suportam coerção de tipos e tags que podem construir objetos arbitrários, a menos que você configure um modo restrito de 'safe load'. Parsers XML caem em ataques de XML External Entity (XXE) se você deixar a expansão de entidades ligada. O sistema de tipos mais simples do JSON (sem tags, sem entidades) remove essas superfícies de ataque, mas os riscos de desserialização e merge descritos aqui continuam valendo.
Experimente estas ferramentas
Artigos relacionados
O que é JSON? Um guia completo para iniciantes →
JSON (JavaScript Object Notation) é um formato leve de troca de dados, fácil de ler por humanos e de analisar por máquinas. Aprenda a sintaxe, os tipos de dados e a estrutura que sustentam as APIs modernas.
A história do JSON: de 2000 a padrão da indústria →
Acompanhe o JSON desde a ideia de Douglas Crockford em 2001, passando pela adoção pelo Yahoo, até se tornar o padrão ECMA-404 que sustenta 90% das APIs modernas.
O guia completo do JSON Schema (Draft 7) →
O JSON Schema é o padrão para descrever e validar a estrutura de JSON. Aprenda as palavras-chave essenciais, construa um schema real de API e aplique as melhores práticas.