30 de out. de 2025·7 min de leitura

Parsing seguro de CSV e JSON: proteja uploads contra entradas maliciosas

Parsing seguro de CSV e JSON evita injeção de fórmulas, linhas malformadas e estouros de memória quando usuários enviam arquivos para seu app.

Parsing seguro de CSV e JSON: proteja uploads contra entradas maliciosas

Por que CSV e JSON enviados por usuários são arriscados

Uploads de usuários não são confiáveis. Isso parece óbvio, mas muda tudo. Dados internos normalmente seguem suas regras porque seu próprio código os produziu. Arquivos enviados vêm de ferramentas desconhecidas, configurações variadas e às vezes com intenção duvidosa.

CSV e JSON também parecem inofensivos porque são "apenas texto". Mas texto ainda pode disparar bugs, gerar registros ruins ou esconder conteúdo que outras partes do sistema executem. Mesmo um arquivo pequeno pode causar dano se atingir um ponto fraco certo, como um caso limite do parser ou uma fórmula de planilha.

Isso vira dor real para o negócio de algumas maneiras comuns: importações que caem e causam indisponibilidade, linhas ruins que poluem o banco silenciosamente, exports que disparam injeção de fórmulas ao abrir em apps de planilha, e uploads grandes que causam lentidão ao carregar tudo na memória.

“Parsing seguro” não significa “meu código consegue ler o arquivo”. Significa que você controla o que acontece quando o arquivo é estranho, hostil ou simplesmente maior do que o esperado. Na prática, trata-se de limites (tamanho, tempo, contagem de linhas), leitura previsível (streaming em vez de carregar tudo de uma vez) e validar cada registro antes de tocar o banco.

Um cenário realista é uma importação de contatos enviada por um cliente. O arquivo pode ter uma célula com uma string de 5 MB, um campo JSON com aninhamento inesperado ou um nome que começa com =HYPERLINK(...). Se você tratar o upload como dado confiável, pode acabar com downtime, limpeza de dados bagunçada e um incidente de segurança.

Principais modos de falha a planejar

Uploads de usuários falham de formas previsíveis. Nomeie-os desde o começo e parsing seguro vira rotina em vez de risco.

CSV malformado é o problema clássico. Arquivos reais frequentemente têm aspas quebradas, vírgulas extras, contagens de colunas desiguais ou encodações estranhas que transformam caracteres em gibberish. Alguns parsers tentam adivinhar o que o usuário quis dizer. Isso pode deslocar colunas silenciosamente e corromper seus dados, ou travar um job de importação quando uma linha está muito malformada.

Injeção de fórmulas em CSV é mais sorrateira. Apps de planilha tratam células que começam com =, +, - ou @ como fórmulas. Se você depois exportar os dados e alguém abrir no Excel ou Google Sheets, um atacante pode plantar uma célula que execute uma fórmula. O perigo costuma ser a etapa a jusante: o fluxo humano.

Armadilhas do JSON aparecem de modo diferente. Objetos profundamente aninhados podem atingir limites de recursão ou disparar uso de CPU. Arrays enormes podem transformar um “upload pequeno” em minutos de processamento. Chaves duplicadas são outro problema: alguns parsers mantêm o primeiro valor, outros o último. Atacantes podem usar essa ambiguidade para contornar validações.

Explosões de memória são o modo de falha mais simples. Ler o arquivo inteiro na memória (ou construir um objeto em memória antes de validar) transforma uploads grandes em timeouts e crashes. Um upload de 50 MB pode ficar bem maior quando parseado.

Um exemplo prático: um upload "contacts.csv" parece ok, mas uma linha tem uma aspa não fechada. Seu parser desloca colunas e agora o campo de e-mail contém partes de outro campo. Ou um "contacts.json" inclui um contato com um array de notas massivo e o uso de memória dispara.

Comece com limites rígidos antes de parsear

A maior parte dos bugs de upload acontece antes do parser ter chance de ajudar. Se você aceita qualquer coisa que pareça uma planilha ou “um JSON qualquer”, convida casos extremos que nunca testou.

Decida o que você realmente suporta. Se uma funcionalidade precisa só de uma tabela simples, aceite CSV e rejeite JSON (e vice-versa). Suportar menos formatos remove muitos cantos estranhos.

Depois, defina limites rígidos que batam com seu uso real. Tamanho de arquivo não é suficiente. Um arquivo pequeno pode ter um milhão de campos minúsculos, e um arquivo de tamanho normal pode expandir muito na memória se você carregar tudo.

Limites que vale a pena impor

Para importações típicas, como contatos, um conjunto pequeno de regras resolve a maior parte dos problemas:

  • Máximo de bytes (baseado nos limites do seu produto)
  • Máximo de linhas e máximo de colunas
  • Comprimento máximo por campo (por célula ou string JSON)
  • Profundidade máxima de aninhamento para JSON
  • Limite de tempo por parse

Encodings são outra armadilha comum. Prefira UTF-8, lide com BOM de UTF-8 e rejeite arquivos que não possam ser decodificados limpos. Decodificação “melhor esforço” silenciosa pode transformar um byte ruim em um delimitador deslocado que quebra todas as linhas.

Rejeite conteúdo inesperado cedo. Para CSV, valide o cabeçalho exatamente (ou a partir de uma pequena allowlist) antes de processar linhas. Para JSON, confirme a forma de topo (objeto vs array) e as chaves obrigatórias antes de tocar o resto.

Registre rejeições sem guardar conteúdo sensível. Salve metadados e motivos (tamanho do arquivo, contagem de linhas, primeira linha com erro, regra que falhou), mas evite manter o upload cru.

Defender contra injeção de fórmulas em CSV

CSV parece inofensivo, mas apps de planilha tratam algumas células como fórmulas. Se um atacante envia um CSV e você depois exporta para alguém abrir, um valor que comece como fórmula pode rodar. Isso é injeção de fórmulas em CSV.

O problema comum não é o parser travar. O perigo é o que acontece depois do parsing, quando um humano abre os dados e a planilha avalia a célula.

Uma regra prática: mantenha o valor original para armazenamento e auditoria, mas crie uma cópia segura para exportação para qualquer lugar onde o valor possa acabar em um CSV que alguém vai abrir numa planilha. Assim você não perde o que o usuário enviou e não entrega um arquivo perigoso para sua equipe.

Ao gerar a cópia segura, trate a célula como arriscada se, após remover espaços e tabs à esquerda, ela começar com qualquer um destes caracteres: =, +, - ou @. Se for arriscada, neutralize prefixando uma aspa simples (') antes do valor no CSV exportado. Muitos apps de planilha então exibem o texto sem executar como fórmula.

Cuidado com entradas dissimuladas. Atacantes frequentemente adicionam espaços, tabs ou caracteres ocultos no início para que a célula pareça normal mas ainda avalie como fórmula. Decida quais caracteres iniciais considerar ignoráveis (pelo menos espaços e tabs) e aplique a verificação na versão limpa.

Teste com payloads que costumam escapar:

  • =HYPERLINK("example","click")
  • +SUM(1,1)
  • -2+3 (parece cálculo)
  • @SUM(1,1)
  • \t=1+1 (espaço ou tab no início)

Tornando parsing de JSON previsível com validação

Enviar um importador de contatos mais seguro
Defina regras claras para cabeçalhos, campos obrigatórios e importações parciais que os usuários entendam.

JSON enviado por usuários não é só dado. É entrada não confiável, e você quer que ele se comporte igual sempre. O objetivo é simples: rejeitar surpresas cedo e aceitar apenas a forma exata que seu app espera.

Comece validando a estrutura antes de usar valores: campos obrigatórios, tipos corretos e um conjunto restrito de valores permitidos. Se seu endpoint espera algo como { "email": string, "role": "admin"|"member" }, não aceite números, arrays ou objetos extras “porque ainda podem funcionar”. É assim que casos extremos viram bugs em produção.

Coloque limites rígidos em JSON caros de processar

Um arquivo JSON pode ser pequeno em bytes mas custoso de parsear, como arrays profundamente aninhados ou strings enormes. Defina limites desde o início:

  • Profundidade máxima de aninhamento
  • Comprimento máximo de string por campo (especialmente notas, bios e metadata)
  • Comprimento máximo de array
  • Máximo de chaves por objeto

Essas verificações mantêm o parsing previsível e protegem memória e CPU.

Trate chaves duplicadas como problema

Payloads JSON podem conter chaves duplicadas, e parsers lidam com isso de formas diferentes (primeiro vence, último vence ou indefinido). Essa ambiguidade pode ser usada para contornar validação. Na maioria dos casos, rejeite payloads com chaves duplicadas para que atacantes não escondam um valor ruim atrás de um bom.

Também evite adivinhação “útil” de tipos. Se você precisa de uma string, mantenha como string. Não converta "00123" em número nem interprete datas implicitamente. Isso muda o significado e pode quebrar lógica a jusante.

Quando a validação falhar, retorne erros claros e seguros para o usuário, como contacts[12].email must be a valid email address. Não exponha stack traces, detalhes SQL ou implementações internas.

Passo a passo: parsing em streaming que não vai travar seu app

Crashes geralmente acontecem porque o servidor tenta ser “útil” e carrega todo o upload na memória. O padrão mais seguro é: aplique limites primeiro e depois processe em pequenas partes.

Comece com uma verificação rápida antes do parsing. Cheque o content-type reportado, mas não confie nele. Aplique um limite máximo rígido de bytes e rejeite arquivos compactados a menos que você possa inspecioná-los com segurança. Também defina um limite de tempo para que um upload lento não ocupe um worker indefinidamente.

Um fluxo prático de streaming

Um fluxo simples que funciona para uploads CSV e JSON:

  • Pré-checar limites: bytes máximos, encodings permitidos e contagem máxima de linhas ou objetos.
  • Fazer streaming a partir do disco ou do corpo da requisição. Não chame "read all" nem construa uma string completa em memória.
  • Parsear registro a registro e parar quando atingir limites rígidos (linhas, campos por linha, profundidade máxima para JSON, comprimento máximo de string).
  • Validar cada registro conforme avança, e coletar apenas uma amostra pequena de erros (por exemplo, os primeiros 20) mais contagens.
  • Gravar dados aceitos incrementalmente: inserções em batch ou empilhar registros válidos numa fila para processamento posterior.

Não tente “consertar” estrutura quebrada enquanto faz streaming. Se o parser reportar entrada malformada, pare e falhe rápido. Importações parciais são aceitáveis só se seu produto explicar isso claramente.

Para uma importação amigável, retorne um resumo: quantos registros foram aceitos, quantos rejeitados e uma pequena lista de erros exemplares com números de linha (ou paths JSON). Por exemplo: "2.431 importados, 17 rejeitados. Principais problemas: email faltando, data inválida, colunas extras."

Regras de validação que mantêm dados ruins fora

Parsing é apenas o primeiro passo. A real vitória em segurança e qualidade vem de tratar cada upload como não confiável e checá-lo contra um contrato claro antes de tocar seu banco.

Escreva o que significa “válido” para seu app. Mantenha isso pequeno e específico, e aplique igual para colunas CSV e campos JSON. Um bom contrato cobre campos permitidos, obrigatórios vs opcionais, regras de tipo e formato (email, telefone, data ISO, moeda), limites de intervalo e limites de comprimento.

Allowlists são importantes porque impedem que campos-surpresa se infiltrem, como uma chave isAdmin inesperada no JSON ou uma coluna role extra no CSV. Se um cabeçalho ou chave não estiver na lista, rejeite o arquivo ou ignore o campo explicitamente e registre isso, mas não aceite silenciosamente.

Normalizações devem ser cuidadosas e previsíveis. Remover espaços e converter TRUE para true é ok, mas evite conversões que mudem significado. Para datas, escolha um formato aceito (ou uma lista curta), normalize para um formato único e seja consistente.

Mensagens de erro devem ajudar o usuário a consertar o arquivo rápido. Em vez de "entrada inválida", retorne algo como: "Linha 17, campo email: esperado [email protected]." Para JSON, aponte um path: "contacts[3].phone está faltando."

Decida desde o início quão estrito você quer ser. Tudo-ou-nada é mais seguro para imports que precisam ser consistentes. Sucesso parcial pode ser melhor para listas de contatos, mas precisa de regras claras (o que é rejeitado, quantos erros você retorna e o que é armazenado).

Erros comuns e armadilhas a evitar

Herdou um protótipo quebrado?
Se seu app Lovable, Bolt, v0, Cursor ou Replit quebrou em produção, nós podemos consertar.

A maioria dos bugs de upload não é uma grande vulnerabilidade. É uma cadeia de pequenas suposições.

Uma armadilha comum é parsear tudo primeiro e só então rodar checagens. Quando a validação falha, dados ruins podem já estar na memória, escritos em uma tabela temporária ou passados para lógica de negócio. Trate validação como parte do parsing: rejeite cedo e pare de ler assim que souber que o arquivo não é aceitável.

Outro erro fácil é confiar no nome do arquivo. Alguém pode enviar um arquivo chamado contacts.csv que na verdade é outra coisa, ou um CSV tão malformado que o parser se comporta de forma estranha. Inspecione o conteúdo (cabeçalhos, delimitadores, primeiros bytes) e aplique uma forma permitida pequena antes de se comprometer a processar.

Algumas armadilhas que reaparecem:

  • Deixar uma biblioteca autodetectar tipos sem limites. Adivinhação pode transformar entradas estranhas em números enormes, datas ou NaN.
  • Re-exportar CSV cru sem proteção contra fórmulas. Armazenar =HYPERLINK(...) é uma coisa; exportar isso para um colega abrir é o ponto perigoso.
  • Carregar o arquivo inteiro para “ter melhores erros”. Um upload gigantesco com pequenos erros em cada linha pode causar picos de memória e timeouts.
  • Retornar relatórios de erro massivos. Listar cada linha ruim para um arquivo enorme cria um segundo problema de memória e pode vazar fragmentos sensíveis.

Um exemplo realista: você importa um "leads.csv" e retorna um erro detalhado por linha. Um atacante envia um arquivo enorme com pequenos erros em cada linha. Seu servidor passa minutos coletando erros, constrói uma resposta multi-megabyte e dá timeout.

Checklist rápido de segurança para uploads CSV e JSON

Se você quer parsing seguro de CSV e JSON, assuma que o arquivo é hostil. A maioria dos bugs de upload não é um hack esperto. São entradas simples que seu código não esperava: arquivos enormes, encodings estranhos ou campos que parecem inofensivos mas disparam comportamento em outras ferramentas.

Mantenha um checklist curto como portão antes dos dados chegarem ao banco:

  • Defina limites rígidos: bytes máximos, linhas/objetos máximos, colunas/campos máximos e (para JSON) profundidade máxima de aninhamento.
  • Parseie em streaming para que um upload não possa disparar memória.
  • Valide estrutura e valores: campos obrigatórios, tipos, limites de comprimento, enums permitidos e formatos de data/número.
  • Neutralize injeção de fórmulas em CSV ao exportar ou re-salvar dados.
  • Falhe fechado: rejeite em caso de parse errors e retorne mensagens pequenas e claras.

Para JSON, “JSON válido” não basta. Um arquivo grande com arrays profundamente aninhados pode ser válido e ainda assim arruinar performance. Limites de profundidade, limites por campo e validação de esquema rígida tornam o parsing previsível.

Depois de live, monitore o básico: timeouts de parsing e parses lentos, taxa de rejeição por motivo e média de linhas/objetos por upload. Esses sinais mostram onde ajustar limites e UX.

Exemplo realista: importação de contatos que permanece segura

Auditoria gratuita de uploads
Analisaremos seu fluxo de upload de CSV e JSON e listaremos os maiores riscos.

Um fundador adiciona um passo "Import contacts" no fluxo de cadastro. Usuários podem enviar um CSV do Excel ou um export JSON de outra ferramenta. O objetivo é simples: criar registros de contato (name, email, company) e pular qualquer coisa insegura.

Um dia chega um CSV com isto na coluna de primeiro nome:

=HYPERLINK("example","Click me")

Se seu app depois exportar esses contatos para CSV para um colega abrir, essa célula pode executar como fórmula. A correção não é "sanitizar depois". Para qualquer campo que possa ser gravado de volta em CSV, ou rejeite valores que comecem com =, +, - ou @, ou armazene uma versão segura para exportação (por exemplo, prefixando com um apóstrofo) e mantenha o original fora dos exports.

Em outro dia, alguém envia um JSON grande. Se seu servidor o ler na memória e parsear tudo de uma vez, pode travar ou cair. Em vez disso, imponha limite de tamanho, parseie como stream, processe contato a contato e pare cedo quando limites forem excedidos (máx. registros, comprimento máximo de campo, profundidade máxima).

O que o usuário vê importa. A página de importação deve mostrar um resumo claro: quantos foram importados, quantos foram pulados e uma amostra pequena de motivos com números de linha ou paths JSON. Nos logs, guarde o que ajuda a depurar sem armazenar dados pessoais. Registre contagens, números de linha, códigos de erro e impressões não identificáveis para detectar padrões sem manter valores crus.

Próximos passos: aperte seu pipeline e peça ajuda se precisar

Trate uploads como uma integração externa. Construa um pequeno conjunto de guardrails que você possa verificar.

Audite os endpoints que aceitam arquivos. Procure por limites claros de tamanho, timeouts, parsing em streaming e lugares onde o arquivo é lido duas vezes ou convertido em uma string gigante antes do parse.

Mantenha um pequeno pacote de testes que você rode a cada mudança: um CSV malformado, um CSV que testa comportamento de injeção de fórmulas, um JSON profundamente aninhado, um JSON com tipos errados e campos faltando, e um arquivo válido grande próximo ao limite. Esses poucos arquivos pegam a maioria das regressões.

Se estiver lidando com uma base de código gerada por IA (especialmente protótipos de ferramentas como Lovable, Bolt, v0, Cursor ou Replit), faça uma revisão extra por limites faltantes, leituras do arquivo inteiro e logging cru. Se quiser uma segunda opinião, FixMyMess (fixmymess.ai) ajuda equipes a diagnosticar e reparar fluxos de importação gerados por IA, incluindo adicionar limites, validação e exportações mais seguras.

Perguntas Frequentes

Por que uploads CSV e JSON são arriscados se são apenas texto?

Trate todo upload como entrada não confiável. Mesmo “apenas texto” pode acionar casos extremos do parser, gerar registros incorretos ou causar problemas mais tarde quando os dados são exportados e abertos em planilhas.

Devo tentar “corrigir automaticamente” arquivos CSV malformados?

Parsing estrito evita deslocamentos silenciosos de dados. Se você tenta adivinhar o que o usuário “quis dizer”, uma aspa faltando ou uma vírgula a mais pode mover valores para colunas erradas e corromper seu banco de dados sem aviso.

Quais limites devo aplicar antes de parsear um arquivo enviado?

Defina limites antes de parsear: bytes máximos, linhas/colunas máximas e tamanho máximo de campo. O tamanho do arquivo sozinho não basta, porque um arquivo pequeno pode conter campos enormes ou crescer muito ao ser processado.

Como evitar que uploads travem meu app por estouros de memória?

Faça streaming e valide enquanto processa. Se você ler o arquivo todo na memória primeiro, um upload grande (ou um pequeno que expanda ao ser parseado) pode causar picos de memória e derrubar o worker ou gerar timeouts.

O que é injeção de fórmulas em CSV, e quando isso realmente importa?

É quando um valor que começa com =, +, - ou @ é exportado e aberto no Excel ou Google Sheets, onde pode ser avaliado como fórmula. O risco normalmente aparece mais adiante no fluxo humano, não durante a importação.

Qual é a forma mais simples de lidar com injeção de fórmulas em CSV ao exportar?

Mantenha o valor original para auditoria, mas gere uma versão segura para exportação. Uma abordagem comum é, após remover espaços/tabs iniciais, prefixar uma aspa simples (') se o valor começar com um caractere de fórmula — assim a planilha exibirá o texto sem executá-lo.

Como tornar o parsing de JSON previsível e seguro?

Valide a forma exata que você espera antes de usar valores, e rejeite surpresas cedo. Aplique limites rígidos em profundidade de aninhamento, comprimento de strings, tamanho de arrays e número total de chaves para que “JSON válido” não seja necessariamente caro de processar.

Devo rejeitar JSON com chaves duplicadas?

Como parsers lidam de forma diferente com chaves duplicadas (primeira vence, última vence ou indefinido), atacantes podem explorar essa ambiguidade. O padrão mais seguro é rejeitar payloads JSON que contenham chaves duplicadas.

Que mensagens de erro devo mostrar quando uma importação falha na validação?

Retorne um resumo claro e pequeno que o usuário consiga agir, indicando qual linha/caminho falhou e por quê. Evite ecoar conteúdo sensível, stack traces ou relatórios massivos por linha que gerem um segundo problema de desempenho.

Quais são os erros mais comuns em código de importação gerado por IA, e como o FixMyMess pode ajudar?

Procure por leituras do arquivo inteiro, falta de limites de tamanho/tempo, logs crus do conteúdo do upload e reexportações para CSV sem proteção contra fórmulas. Se o código de importação foi gerado por IA e é instável em produção, FixMyMess pode auditar rapidamente e reparar limites, streaming, validação e manipulação segura de exportações.