Segurança de XML e JSON
A aula aborda os principais riscos de segurança ao manipular XML e JSON, incluindo parsing inseguro, ataques XXE, validação de esquemas JSON e boas práticas de validação. São apresentados exemplos práticos de vulnerabilidades e como mitigá-las, além de exercícios para fixação.
XML e JSON são formatos de dados amplamente utilizados em APIs, configurações e troca de informações entre sistemas. Embora sejam simples e poderosos, o manuseio incorreto desses formatos pode introduzir graves vulnerabilidades de segurança, como injeção de entidades externas (XXE) e processamento de dados malformados. Esta aula explora os principais riscos e as melhores práticas para garantir a segurança ao lidar com XML e JSON.
Vamos abordar desde o parsing (análise) dos dados até a validação de esquemas, passando por ataques conhecidos e como se proteger. O foco é prático: você verá exemplos de código vulnerável e as correções necessárias para torná-lo seguro.
Parsing
Parsing (ou análise) é o processo de interpretar um documento XML ou JSON e convertê-lo em uma estrutura de dados utilizável pelo programa. Durante esse processo, o parser lê o conteúdo e o interpreta de acordo com as regras da linguagem. No entanto, parsers mal configurados podem ser explorados por atacantes para executar ações não intencionais, como acessar arquivos locais ou causar negação de serviço.
No contexto de XML, o padrão XML permite a definição de entidades personalizadas, que podem ser usadas para referenciar conteúdo externo. Se o parser não for configurado para desabilitar essas entidades, um atacante pode enviar um documento malicioso que faça o parser ler arquivos do servidor ou fazer requisições a serviços internos. Esse é o famoso ataque XXE (XML External Entity).
Para JSON, o parsing é geralmente mais seguro, pois o formato não possui um mecanismo de entidades externas. No entanto, parsers podem ter vulnerabilidades de implementação, como estouro de buffer ou consumo excessivo de memória, se não forem limitados em tamanho e profundidade. Portanto, é essencial usar bibliotecas de parsing atualizadas e configurá-las com limites adequados.
Exemplo de parsing seguro em Python com defusedxml para XML:
from defusedxml.ElementTree import parse
tree = parse('documento.xml')
root = tree.getroot()
print(root.tag)Em contraste, o uso do parser padrão xml.etree.ElementTree é vulnerável a XXE. A biblioteca defusedxml desabilita entidades externas por padrão, protegendo o sistema.
Para JSON, em Python, o módulo json é seguro, mas é importante limitar o tamanho do payload e a profundidade do aninhamento para evitar ataques de DoS:
import json
dados = json.loads(texto)
# Considere usar limites de tamanho e profundidade
XXE
XXE (XML External Entity) é uma vulnerabilidade que ocorre quando um parser XML processa entidades externas definidas no documento. Essas entidades podem referenciar arquivos locais, URLs ou até mesmo executar comandos no servidor, dependendo da configuração. O ataque é possível quando o parser permite a resolução de entidades sem restrições.
Um exemplo clássico de documento XML malicioso que tenta ler o arquivo /etc/passwd:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<foo>&xxe;</foo>Se o parser não estiver protegido, ele substituirá &xxe; pelo conteúdo do arquivo, expondo informações sensíveis.
Para mitigar o XXE, as seguintes medidas são essenciais:
- Desabilitar entidades externas e DTDs no parser.
- Usar bibliotecas que já são seguras por padrão, como
defusedxmlem Python oulibxml2com opções seguras. - Validar e restringir o conteúdo do XML, rejeitando DOCTYPE e entidades personalizadas.
Exemplo de configuração segura em Java com o parser DocumentBuilderFactory:
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);Além disso, é importante validar o XML contra um esquema (XSD) para garantir que ele siga a estrutura esperada, mas isso não é suficiente para impedir XXE, pois a validação pode não rejeitar entidades.
JSON schema
JSON Schema é uma especificação que permite descrever a estrutura de dados JSON, definindo tipos, propriedades obrigatórias, intervalos de valores e outras restrições. Ele é análogo ao XSD para XML, mas adaptado ao formato JSON. O uso de JSON Schema é uma prática recomendada para validar a entrada de dados em APIs, garantindo que apenas dados bem formados e dentro das regras sejam aceitos.
Um exemplo simples de JSON Schema que valida um objeto com nome (string) e idade (inteiro):
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"nome": { "type": "string" },
"idade": { "type": "integer", "minimum": 0 }
},
"required": ["nome", "idade"]
}Com esse esquema, podemos validar se um JSON recebido está em conformidade. Por exemplo, o JSON {"nome": "Ana", "idade": 30} é válido, mas {"nome": "Ana"} não é, pois falta a idade.
A validação de JSON Schema não é uma medida de segurança por si só, mas ajuda a prevenir que dados inesperados ou malformados entrem no sistema, reduzindo a superfície de ataque. Por exemplo, se a aplicação espera um número e recebe uma string, isso pode causar erros não tratados ou até injeção de comandos se os dados forem usados em consultas.
Além disso, JSON Schema pode ser usado para limitar o tamanho de strings, números em faixas seguras e até mesmo padrões de expressões regulares, evitando valores extremos que possam causar problemas de desempenho.
Validation
Validação é o processo de verificar se os dados fornecidos estão de acordo com as regras esperadas antes de serem processados ou armazenados. No contexto de XML e JSON, a validação deve ser realizada em duas camadas: sintática e semântica. A validação sintática garante que o documento está bem formado e segue a estrutura definida (por exemplo, por um esquema). A validação semântica verifica se os valores fazem sentido no contexto da aplicação, como faixas de idade ou formatos de e-mail.
Para XML, a validação pode ser feita com XSD (XML Schema Definition) ou Relax NG. Um exemplo de XSD para um elemento pessoa:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="pessoa">
<xs:complexType>
<xs:sequence>
<xs:element name="nome" type="xs:string"/>
<xs:element name="idade" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>Para JSON, a validação com JSON Schema já foi apresentada. Além disso, é comum usar bibliotecas de validação específicas em cada linguagem, como jsonschema em Python ou Ajv em JavaScript.
É importante notar que a validação não deve ser a única camada de segurança. Ela deve ser combinada com outras práticas, como sanitização de entrada, uso de prepared statements para consultas SQL e controle de acesso. A validação ajuda a reduzir a chance de exploração de vulnerabilidades, mas não elimina todas.
Exemplo de validação de JSON Schema em Python:
import jsonschema
from jsonschema import validate
schema = {
"type": "object",
"properties": {
"nome": {"type": "string"},
"idade": {"type": "integer", "minimum": 0}
},
"required": ["nome", "idade"]
}
dados = {"nome": "João", "idade": 25}
validate(instance=dados, schema=schema)Se os dados não forem válidos, uma exceção será lançada, e a aplicação pode tratá-la adequadamente.
Boas práticas e observações finais
Além das técnicas específicas para XML e JSON, algumas boas práticas gerais ajudam a melhorar a segurança:
- Use bibliotecas de parsing confiáveis e mantenha-as atualizadas.
- Configure os parsers com limites de tamanho e profundidade para evitar ataques de negação de serviço.
- Sempre valide a entrada antes de processá-la, utilizando esquemas sempre que possível.
- Prefira JSON em vez de XML quando possível, pois o JSON tem uma superfície de ataque menor.
- Eduque sua equipe sobre os riscos de XXE e outras vulnerabilidades de parsing.
Lembre-se de que segurança é um processo contínuo. Testes de segurança, como fuzzing e análise estática, podem ajudar a identificar vulnerabilidades antes que sejam exploradas.
Referências
- OWASP: XML External Entity (XXE) Processing
- W3C XML Schema
- JSON Schema
- Python XML Processing
- Python JSON module
- defusedxml library
- Ajv JSON schema validator
Exercícios
- Explique o que é o ataque XXE e cite duas medidas de mitigação.
- Qual a diferença entre validação sintática e semântica? Dê um exemplo de cada para JSON.
- Escreva um JSON Schema que valide um objeto com campos "nome" (string), "idade" (inteiro entre 0 e 150) e "email" (string com formato de e-mail).
- Em Python, usando
defusedxml, como você faria para ler um XML com segurança? Escreva o código. - Cite três boas práticas para evitar vulnerabilidades ao lidar com XML e JSON.
defusedxml.{
"type": "object",
"properties": {
"nome": { "type": "string" },
"idade": { "type": "integer", "minimum": 0, "maximum": 150 },
"email": { "type": "string", "format": "email" }
},
"required": ["nome", "idade", "email"]
}from defusedxml.ElementTree import parse
tree = parse('arquivo.xml')
root = tree.getroot()
print(root.tag)