Skip to content
jsonforge.app
Voltar ao blog
Guia7 min de leitura

Segurança em JSON: vulnerabilidades comuns e como evitá-las

O JSON em si não tem código executável, ao contrário do XML com seus riscos de entidade externa ou do YAML com suas surpresas de coerção de tipos — por isso tem fama de ser intrinsecamente seguro de analisar. Essa fama é majoritariamente merecida para a etapa de análise em si, mas o que seu código faz com o objeto analisado depois é onde vivem as vulnerabilidades reais.

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 se proteger contra chaves especiais, um atacante pode injetar propriedades no próprio Object.prototype — afetando todo objeto da sua aplicação, não apenas aquele que recebeu o merge.

Um payload malicioso visando uma função ingênua de deep-merge.
json
{
  "__proto__": {
    "isAdmin": true
  }
}

Se isso for mesclado com deep-merge num objeto de usuário usando um merge recursivo que não trata especialmente as chaves __proto__, constructor ou prototype, todo objeto do processo — incluindo os que nunca tocaram esse payload específico — pode de repente ter uma propriedade isAdmin com valor true. Essa já foi uma classe real 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 que a poluição possa alcançar. Prefira Map a objetos simples quando as chaves vêm de entrada do usuário e você não precisa de serialização JSON no resultado. Se você precisar fazer deep-merge de JSON não confiável num objeto existente, use uma utilidade de merge que bloqueie explicitamente __proto__, constructor e prototype como chaves — verifique se sua dependência já corrigiu isso (a maioria das bibliotecas principais corrigiu, nas versões recentes) em vez de assumir que está resolvido. Mantenha as dependências em dia: essa exata classe de vulnerabilidade foi corrigida múltiplas vezes em pacotes populares conforme novas técnicas de bypass foram descobertas.

Desserialização insegura além do JSON.parse puro

O JSON.parse() puro só 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, por exemplo, pode executar código arbitrário durante a 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 — por exemplo, um campo "type" no JSON usado para fazer require() dinâmico ou despachar para um handler por nome de string sem validar que a string está numa allowlist.

Valide contra um schema antes de confiar em JSON não confiável

JSON.parse() garante apenas validade sintática — ele não diz 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 com uma string onde se esperava um número, pode derrubar código downstream ou produzir silenciosamente comportamento errado. Validar JSON de entrada contra um schema (JSON Schema, Zod, Joi ou similar) antes de usá-lo captura estrutura malformada ou inesperada na fronteira, dá a você um ponto de rejeição claro com uma mensagem de erro útil em vez de um crash confuso três funções adiante, e ainda funciona como documentação viva do formato que o endpoint de fato 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. Nunca 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 os valores sejam verificados contra uma allowlist. Mantenha atualizadas as dependências de manipulação de JSON (parsers, utilidades de merge, validadores de schema) — essa é uma classe de vulnerabilidade em evolução ativa. Defina limites de tamanho razoáveis para corpos de requisição JSON, para reduzir a exposição a ataques de exaustão de recursos via payloads extremamente grandes ou profundamente 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?
É uma vulnerabilidade em que entrada controlada por um atacante (frequentemente JSON com uma chave __proto__) é mesclada num objeto usando código que não se protege contra nomes de propriedade especiais, permitindo que o atacante adicione ou sobrescreva propriedades no objeto base compartilhado do qual todos os objetos JavaScript herdam — afetando a aplicação inteira, não apenas um objeto.
Preciso de validação de schema se já uso TypeScript?
Sim — os tipos do TypeScript são apagados em tempo de compilação e oferecem proteção zero em tempo de execução. Um payload JSON malformado ou malicioso chegando via HTTP não é verificado por nada em runtime, a menos que você o valide explicitamente 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 faz nada para verificar que os dados reais correspondem a esse formato.
YAML ou XML são mais seguros que JSON para analisar?
Não intrinsecamente — 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 se não configurados num modo restrito de 'safe load'. Parsers XML são vulneráveis a ataques de XML External Entity (XXE) se a expansão de entidades não for desabilitada. O sistema de tipos mais simples do JSON (sem tags, sem entidades) remove essas superfícies de ataque específicas, mas os riscos de desserialização e merge cobertos aqui continuam valendo.

Experimente estas ferramentas

Artigos relacionados