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.







