XML e JSON são formatos de dados amplamente utilizados em APIs, configurações e troca de informações entre sistemas. Embora sejam essenciais para a interoperabilidade, o processamento inadequado desses formatos pode introduzir graves vulnerabilidades de segurança, como a injeção de entidades externas (XXE) e a validação insuficiente de dados. Nesta aula, vamos explorar os principais riscos associados ao parsing de XML e JSON, as melhores práticas para mitigá-los e como usar ferramentas como JSON Schema para garantir a integridade dos dados.

Entender esses conceitos é fundamental para qualquer desenvolvedor ou profissional de segurança, pois a maioria dos sistemas modernos depende desses formatos para comunicação e armazenamento. Vamos começar com o parsing, depois mergulhar no XXE, em seguida discutir o JSON Schema e, por fim, as estratégias de validação. Ao final, você terá um guia prático para proteger suas aplicações contra ataques comuns.

Parsing

O parsing é o processo de analisar uma string ou fluxo de dados em uma estrutura compreensível pela aplicação, como um objeto ou árvore. No contexto de XML, o parser lê a estrutura hierárquica de elementos, atributos e texto. Já no JSON, o parser converte o texto em objetos JavaScript ou equivalentes em outras linguagens. Embora pareça simples, a escolha do parser e a forma como ele é configurado têm implicações profundas na segurança.

Parsers inseguros podem ser explorados para causar negação de serviço (via bomba XML), leitura de arquivos locais (XXE) ou execução de código. Por isso, é crucial utilizar parsers que não processem entidades externas por padrão e que limitem a profundidade e o tamanho dos dados. Em linguagens como Java, por exemplo, o DocumentBuilderFactory pode ser configurado para desabilitar DTDs e entidades externas. No Python, a biblioteca padrão xml.etree.ElementTree é segura contra XXE, mas outras como lxml requerem configuração.

Exemplo de configuração segura em Java:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(new File("input.xml"));

No JSON, o parsing é geralmente mais simples, mas ainda assim é importante usar a função nativa JSON.parse (em JavaScript) ou equivalentes que não executem código. Evite usar eval() para parsear JSON, pois isso pode levar à execução de código arbitrário.

XXE

XXE (XML External Entity) é uma vulnerabilidade que ocorre quando um parser XML processa entidades externas definidas em um DOCTYPE. Essas entidades podem referenciar arquivos locais, URLs internas ou até mesmo executar comandos. O impacto pode ser a divulgação de informações sensíveis, SSRF (Server-Side Request Forgery) ou negação de serviço.

Um exemplo clássico de ataque XXE é enviar um XML como o seguinte:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>

Se o parser não estiver configurado para bloquear DTDs, ele substituirá &xxe; pelo conteúdo do arquivo /etc/passwd, expondo-o na resposta. Para prevenir, é essencial desabilitar DTDs e entidades externas em todos os parsers XML. Em bibliotecas como libxml2, você pode usar opções como XML_PARSE_NOENT e XML_PARSE_DTDLOAD desabilitadas.

Além disso, recomenda-se usar formatos mais modernos como JSON, que não têm esse tipo de vulnerabilidade, ou validar rigorosamente o XML recebido antes do parsing. A OWASP fornece uma folha de dicas (cheat sheet) sobre prevenção de XXE, que é um excelente guia de referência.

Exemplo de verificação em Python usando defusedxml:

from defusedxml.ElementTree import parse

tree = parse('input.xml')  # defusedxml bloqueia XXE automaticamente

JSON schema

JSON Schema é uma especificação que permite descrever a estrutura e as restrições de um documento JSON. Ele funciona como um contrato que define quais campos são obrigatórios, seus tipos, formatos, etc. Usar JSON Schema é uma prática recomendada para validar dados recebidos de fontes externas, pois garante que apenas dados bem formados e esperados sejam aceitos.

Com JSON Schema, você pode definir regras como: o campo "email" deve ser uma string válida de email, "idade" deve ser um número inteiro entre 0 e 120, etc. Isso ajuda a evitar dados maliciosos ou corrompidos que possam quebrar a aplicação ou explorar vulnerabilidades. Existem implementações de JSON Schema em várias linguagens, como Ajv para JavaScript, jsonschema para Python, e Json.NET Schema para .NET.

Um exemplo simples de schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "nome": { "type": "string" },
    "email": { "type": "string", "format": "email" },
    "idade": { "type": "integer", "minimum": 0, "maximum": 120 }
  },
  "required": ["nome", "email"]
}

Esse schema valida que o JSON seja um objeto com nome (string), email (string com formato email) e idade (inteiro entre 0 e 120). O campo nome e email são obrigatórios.

Além de validar a estrutura, o JSON Schema pode ser usado para documentar APIs e gerar código automaticamente, melhorando a consistência e a segurança.

Validation

A validação vai além do parsing: é o processo de garantir que os dados atendam a regras de negócio e sejam seguros para uso. Para XML, isso pode incluir a validação contra um XSD (XML Schema Definition) ou DTD. Para JSON, o JSON Schema é a ferramenta padrão. No entanto, a validação não deve ser apenas estrutural; também é preciso verificar conteúdo, tamanho e tipos de dados para evitar ataques como injeção de SQL ou XSS.

Um erro comum é confiar apenas no parsing e ignorar a validação semântica. Por exemplo, um campo que deveria ser um número pode conter milhões de dígitos, causando estouro de memória. Ou um campo de string pode conter scripts maliciosos que serão renderizados em páginas web. Portanto, a validação deve incluir limites de tamanho, formatos e valores permitidos.

No lado do servidor, sempre valide os dados recebidos antes de usá-los em consultas, comandos ou renderização. Nunca confie em dados do cliente. Use bibliotecas de validação robustas e configure-as para rejeitar entradas inválidas de forma explícita.

Exemplo de validação de tamanho em JSON Schema:

{
  "type": "object",
  "properties": {
    "comentario": { "type": "string", "maxLength": 500 }
  }
}

Isso impede que o campo "comentario" tenha mais de 500 caracteres, evitando abusos.

Boas Práticas

Algumas práticas recomendadas para garantir a segurança no processamento de XML e JSON incluem:

  • Utilizar bibliotecas seguras e atualizadas, como defusedxml em Python ou JAXP com configurações seguras em Java.
  • Desabilitar recursos perigosos em parsers XML: DTDs, entidades externas, XInclude, etc.
  • Para JSON, evitar eval() e usar JSON.parse ou equivalentes.
  • Definir limites de tamanho de entrada e complexidade (ex.: profundidade máxima em XML).
  • Validar dados tanto no cliente quanto no servidor, mas nunca confiar no cliente.
  • Usar JSON Schema para validar a estrutura e o conteúdo de JSON.
  • Manter-se atualizado sobre as vulnerabilidades conhecidas e as correções dos frameworks.

Referências

Exercícios

  1. Explique o que é XXE e dê um exemplo de como um atacante pode explorar essa vulnerabilidade.
  2. ✓ Resposta: XXE (XML External Entity) é uma vulnerabilidade que permite a um atacante inserir entidades externas em um documento XML, que podem ser processadas pelo parser, resultando na leitura de arquivos locais, execução de requisições SSRF ou até mesmo negação de serviço. Por exemplo, um atacante pode enviar um XML com uma entidade que referencia file:///etc/passwd e, se o parser não estiver configurado para bloquear DTDs, o conteúdo do arquivo será retornado na resposta.
  3. Quais são as principais medidas para prevenir ataques XXE em parsers XML?
  4. ✓ Resposta: As principais medidas incluem: desabilitar DTDs e entidades externas no parser; usar bibliotecas seguras como defusedxml; configurar o parser para não permitir XInclude; e validar o XML antes do parsing. Também é recomendado usar formatos alternativos como JSON quando possível.
  5. O que é JSON Schema e como ele ajuda na segurança de aplicações?
  6. ✓ Resposta: JSON Schema é uma especificação que define a estrutura e as restrições de dados JSON. Ele ajuda na segurança ao garantir que os dados recebidos atendam a um contrato, evitando que dados malformados ou maliciosos sejam processados. Por exemplo, pode-se exigir que um campo seja uma string com formato de email, reduzindo riscos de injeção.
  7. Dê um exemplo de um JSON Schema que valide um objeto com campos nome (string), idade (inteiro) e email (string com formato email), sendo nome e email obrigatórios.
  8. ✓ Resposta: O JSON Schema seria:
    {
      "type": "object",
      "properties": {
        "nome": { "type": "string" },
        "idade": { "type": "integer" },
        "email": { "type": "string", "format": "email" }
      },
      "required": ["nome", "email"]
    }
  9. Por que é importante validar dados mesmo após o parsing? Dê um exemplo de um ataque que pode ser evitado com validação adicional.
  10. ✓ Resposta: A validação é importante porque o parsing apenas converte dados em estrutura; não garante que os dados sejam seguros ou esperados. Por exemplo, um campo de nome pode conter uma tag <script> que, se renderizada sem escapar, pode causar XSS. Validar o conteúdo (ex.: limites de tamanho, caracteres permitidos) pode evitar esse tipo de ataque.