xmlrpc.server: crie servidores XML-RPC

Publicado em: 21/08/2026
Tempo de leitura: 6 minutos
Rack de servidores representando um endpoint criado com xmlrpc.server no Python

O módulo xmlrpc.server oferece um framework básico para criar servidores XML-RPC em Python. Ele recebe chamadas HTTP POST com XML, converte parâmetros em objetos Python, executa uma função registrada e serializa o resultado. É útil em integrações legadas, testes locais e sistemas internos que já dependem do protocolo.

A documentação oficial alerta que o módulo não é seguro contra XML maliciosamente construído. Além disso, SimpleXMLRPCServer não fornece sozinho autenticação moderna, limitação de taxa, proteção contra abuso ou uma arquitetura pronta para internet pública. Trate-o como componente interno, atrás de controles adicionais.

Servidor mínimo

from xmlrpc.server import SimpleXMLRPCServer

with SimpleXMLRPCServer(
    ("127.0.0.1", 8000),
    allow_none=False,
    logRequests=False,
    use_builtin_types=True,
) as servidor:

    @servidor.register_function(name="somar")
    def somar(a: int, b: int) -> int:
        return a + b

    servidor.serve_forever()

O bind em 127.0.0.1 impede acesso direto de outras máquinas. Para produção interna, coloque um proxy reverso autenticado na frente e mantenha o processo em rede restrita.

Restringindo o caminho RPC

Por padrão, o handler aceita / e /RPC2. Uma subclasse pode limitar a apenas um caminho.

from xmlrpc.server import (
    SimpleXMLRPCRequestHandler,
    SimpleXMLRPCServer,
)

class Handler(SimpleXMLRPCRequestHandler):
    rpc_paths = ("/RPC2",)

servidor = SimpleXMLRPCServer(
    ("127.0.0.1", 8000),
    requestHandler=Handler,
)

A restrição reduz endpoints acidentais, mas não substitui autenticação. Um atacante que alcança o caminho ainda pode enviar chamadas.

Registro explícito de funções

Prefira register_function() com nomes claros. Isso cria uma allowlist de operações expostas.

def status() -> dict[str, object]:
    return {"ok": True, "versao": "1"}

servidor.register_function(status, "sistema.status")

Valide tipos, faixas, tamanho de strings e quantidade de itens dentro da função. Anotações de tipo não validam automaticamente os dados recebidos.

Não exponha funções perigosas

Evite registrar funções que executam comandos, abrem caminhos arbitrários, avaliam código, importam módulos ou recebem SQL cru. O XML-RPC é apenas transporte; os riscos da função continuam existindo.

from pathlib import Path

RAIZ = Path("/srv/relatorios").resolve()

def ler_relatorio(nome: str) -> str:
    if not nome.endswith(".txt") or "/" in nome or "\\" in nome:
        raise ValueError("nome inválido")
    caminho = (RAIZ / nome).resolve()
    if RAIZ not in caminho.parents:
        raise ValueError("caminho fora da raiz")
    return caminho.read_text(encoding="utf-8")

Mesmo em rede interna, considere todos os parâmetros não confiáveis.

register_instance e _dispatch

register_instance() pode expor métodos de um objeto. Uma abordagem mais segura é implementar _dispatch() e mapear manualmente nomes permitidos.

class Servico:
    def _dispatch(self, metodo, parametros):
        permitidos = {
            "sistema.status": self.status,
            "calcular.soma": self.soma,
        }
        funcao = permitidos.get(metodo)
        if funcao is None:
            raise ValueError("método não permitido")
        return funcao(*parametros)

    def status(self):
        return {"ok": True}

    def soma(self, a, b):
        return int(a) + int(b)

servidor.register_instance(Servico())

A allowlist impede que atributos internos sejam descobertos por nome.

Nunca habilite allow_dotted_names em rede aberta

A própria documentação alerta que allow_dotted_names=True pode permitir acesso a variáveis globais e até execução arbitrária. Mantenha o padrão False. Se um sistema antigo exigir nomes hierárquicos, implemente-os por registro explícito ou _dispatch().

Introspecção

register_introspection_functions() expõe system.listMethods, system.methodHelp e system.methodSignature.

servidor.register_introspection_functions()

Isso ajuda em desenvolvimento, mas revela superfície de métodos. Em produção, habilite apenas se houver necessidade e autorização adequada. Documentação pública não deve incluir operações administrativas.

Multicall

register_multicall_functions() habilita system.multicall, permitindo várias operações em uma única requisição.

servidor.register_multicall_functions()

O recurso reduz viagens de rede, mas aumenta o trabalho de uma chamada. Aplique limite de quantidade, custo e tamanho. Não misture operações destrutivas sem definir atomicidade e comportamento de falha parcial.

Tipos e allow_none

XML-RPC suporta tipos limitados. allow_none=True habilita uma extensão para None, que nem todo cliente implementa. use_builtin_types=True facilita datas e bytes.

Defina o contrato por método: tipos aceitos, limites, timezone de datas, tamanho máximo de binários e significado de valores ausentes. Para arquivos grandes, prefira upload dedicado.

Falhas e mensagens

Exceções lançadas pelas funções são transformadas em faults XML-RPC. Não devolva stack traces, caminhos, queries ou segredos. Converta falhas conhecidas em códigos estáveis.

from xmlrpc.client import Fault

def buscar_usuario(usuario_id: int):
    if usuario_id <= 0:
        raise Fault(400, "identificador inválido")
    usuario = repositorio.buscar(usuario_id)
    if usuario is None:
        raise Fault(404, "usuário não encontrado")
    return usuario

A mensagem ainda deve ser escapada ao aparecer em HTML no cliente.

Autenticação

SimpleXMLRPCServer não traz uma solução completa de autenticação. A opção mais segura é colocar o processo atrás de Nginx, Apache, API gateway ou service mesh que valide mTLS, Basic Auth, token ou identidade de rede.

Uma subclasse de request handler pode verificar headers, mas cuidado para não registrar credenciais. Mantenha a lógica centralizada e teste respostas 401 e 403.

TLS

O servidor simples não configura HTTPS diretamente de forma ergonômica. Prefira terminar TLS em um proxy reverso atualizado, com certificado, versões modernas, limite de corpo, timeout e logs.

Se envolver o socket manualmente, você assume detalhes de handshake, shutdown e atualização. O guia de ssl no Python explica os riscos.

Limite de corpo e XML malicioso

O aviso da documentação deve ser levado a sério. XML pode ser construído para consumir memória ou CPU. Coloque limite de Content-Length no proxy, rejeite transferências sem política, configure timeout e limite conexões simultâneas.

Não exponha o servidor a clientes anônimos. Segmentação de rede e autenticação reduzem a probabilidade de receber payloads hostis, mas não substituem limites.

Concorrência

SimpleXMLRPCServer é baseado em socketserver.TCPServer e processa requisições de forma síncrona. Uma chamada lenta bloqueia as seguintes.

from socketserver import ThreadingMixIn
from xmlrpc.server import SimpleXMLRPCServer

class ServidorComThreads(ThreadingMixIn, SimpleXMLRPCServer):
    daemon_threads = True

Threads aumentam concorrência, mas também risco de corrida, consumo e sobrecarga. Proteja estado compartilhado, limite conexões e evite tarefas longas. O guia de socketserver no Python detalha mixins e encerramento.

Timeouts e tarefas longas

Não execute relatórios extensos, processamento de vídeo ou operações indefinidas dentro da thread da requisição. Enfileire o trabalho, retorne um identificador e ofereça um método de consulta. Defina timeout no proxy e no cliente.

Encerramento seguro

Use o servidor como context manager e chame shutdown() a partir de outra thread quando serve_forever() estiver ativo. Depois, feche recursos de aplicação.

try:
    servidor.serve_forever()
except KeyboardInterrupt:
    pass
finally:
    servidor.server_close()

Em ambientes gerenciados, trate SIGTERM e pare de aceitar novas chamadas antes de encerrar.

Logs

logRequests=True registra requisições de forma simples. Em produção, prefira logging estruturado com método lógico, duração, resultado e identificador de correlação. Não registre corpo XML completo, tokens ou dados pessoais.

Documentação automática

DocXMLRPCServer gera uma página HTML de documentação para GET. É conveniente em laboratórios, mas pode revelar métodos e textos internos. Não exponha essa página sem autenticação e revisão.

Cliente correspondente

Para consumir o serviço, use xmlrpc.client no Python. O cliente deve usar HTTPS, timeout, allowlist de métodos e tratamento separado de Fault e ProtocolError.

Testes recomendados

Teste método válido e inexistente, parâmetros fora de faixa, corpo grande, XML malformado, autenticação ausente, caminho incorreto, chamadas simultâneas, multicall excessivo, shutdown e ausência de segredos nos faults e logs.

Faça testes locais e nunca use um servidor público de terceiros para validar código destrutivo.

Quando escolher outra tecnologia

Para uma API nova, frameworks HTTP com JSON, schemas e middleware de segurança costumam ser mais adequados. XML-RPC é indicado principalmente para compatibilidade com sistemas existentes ou ferramentas internas simples em rede controlada.

Conclusão

xmlrpc.server permite construir rapidamente um endpoint RPC, mas a rapidez não elimina responsabilidades de segurança. Registre funções explicitamente, mantenha allow_dotted_names desativado, limite caminhos e payloads, autentique no proxy, proteja TLS, controle concorrência e trate XML como não confiável.

Consulte a documentação oficial de xmlrpc.server e as orientações de segurança para XML no Python. Para internet pública ou projetos novos, considere uma plataforma de API com controles mais completos.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Desenvolvedor configurando servidor HTTPS e certificado TLS com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crie servidor HTTPS local no Python

    Aprenda HTTPSServer no Python para servir HTTPS localmente, configurar certificados, usar threads e entender limites de segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    08/10/2026
    Arquivos protegidos representando extração segura de TAR com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extraia TAR com segurança

    Aprenda tarfile extraction_filter no Python para extrair arquivos TAR com validação, segurança e controle de caminhos.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python exibindo avisos controlados com catch_warnings
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: capture warnings em testes Python

    Aprenda catch_warnings no Python para capturar, testar e controlar avisos com filtros específicos e segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python representando referências persistentes do pickle
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serialize referências externas

    Aprenda pickle persistent_id no Python para serializar referências externas com IDs estáveis, validação, segurança e compatibilidade.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binário representando buffers e memória no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: conte valores sem copiar buffers

    Aprenda memoryview.count no Python para contar bytes e valores em buffers sem cópias, com formatos, limites e boas práticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python com anotações de tipos
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evite imports circulares em anotações

    Aprenda annotationlib no Python para ler anotações adiadas, evitar imports circulares e criar ferramentas de introspecção seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026