El módulo xmlrpc.server ofrece un framework básico para crear servidores XML-RPC en Python. Recibe peticiones HTTP POST con XML, convierte parámetros en objetos Python, ejecuta una función registrada y serializa el resultado. Puede servir para integraciones heredadas, pruebas locales y sistemas internos controlados que ya dependen del protocolo.
La documentación oficial advierte que el módulo no es seguro frente a XML construido de forma maliciosa. Además, SimpleXMLRPCServer no proporciona por sí solo autenticación moderna, rate limiting, protección contra abuso ni una arquitectura preparada para internet pública. Trátalo como un componente interno detrás de controles adicionales.
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="sumar")
def sumar(a: int, b: int) -> int:
return a + b
servidor.serve_forever()
El bind en 127.0.0.1 impide conexiones directas desde otras máquinas. Para un servicio interno de producción, coloca un proxy reverso autenticado delante y mantiene el proceso en una red restringida.
Restringir la ruta RPC
El handler por defecto acepta / y /RPC2. Una subclase puede permitir solo una ruta.
from xmlrpc.server import (
SimpleXMLRPCRequestHandler,
SimpleXMLRPCServer,
)
class Handler(SimpleXMLRPCRequestHandler):
rpc_paths = ("/RPC2",)
servidor = SimpleXMLRPCServer(
("127.0.0.1", 8000),
requestHandler=Handler,
)
La restricción elimina endpoints accidentales, pero no sustituye autenticación. Un cliente que alcance la ruta aún puede enviar llamadas.
Registro explícito de funciones
Prefiere register_function() con nombres públicos claros. Esto crea una allowlist de operaciones expuestas.
def estado() -> dict[str, object]:
return {"ok": True, "version": "1"}
servidor.register_function(estado, "sistema.estado")
Valida tipos, rangos, longitudes de strings y cantidades de elementos dentro de cada función. Las anotaciones de tipo no validan automáticamente los parámetros RPC.
No expongas funciones peligrosas
Evita registrar funciones que ejecuten comandos, abran rutas arbitrarias, evalúen código, importen módulos o acepten SQL crudo. XML-RPC es solo el transporte; los riesgos de la operación permanecen.
from pathlib import Path
RAIZ = Path("/srv/informes").resolve()
def leer_informe(nombre: str) -> str:
if not nombre.endswith(".txt") or "/" in nombre or "\\" in nombre:
raise ValueError("nombre inválido")
ruta = (RAIZ / nombre).resolve()
if RAIZ not in ruta.parents:
raise ValueError("ruta fuera de la raíz")
return ruta.read_text(encoding="utf-8")
Incluso en red interna, considera todos los parámetros no confiables.
register_instance y _dispatch
register_instance() puede exponer métodos de un objeto. Un diseño más seguro implementa _dispatch() y mapea manualmente nombres permitidos.
class Servicio:
def _dispatch(self, metodo, parametros):
permitidos = {
"sistema.estado": self.estado,
"calcular.suma": self.suma,
}
funcion = permitidos.get(metodo)
if funcion is None:
raise ValueError("método no permitido")
return funcion(*parametros)
def estado(self):
return {"ok": True}
def suma(self, a, b):
return int(a) + int(b)
servidor.register_instance(Servicio())
La allowlist evita que atributos internos puedan descubrirse remotamente.
Nunca actives allow_dotted_names en red abierta
La documentación de Python advierte expresamente que allow_dotted_names=True puede exponer variables globales del módulo y permitir ejecución arbitraria. Mantén el valor por defecto False. Si un cliente antiguo necesita nombres jerárquicos, regístralos explícitamente o implementa un _dispatch() controlado.
Introspección
register_introspection_functions() expone system.listMethods, system.methodHelp y system.methodSignature.
servidor.register_introspection_functions()
Ayuda durante desarrollo, pero revela superficie de métodos. Actívala en producción solo cuando sea necesaria y esté protegida. La documentación pública no debe listar operaciones administrativas accidentalmente.
Multicall
register_multicall_functions() habilita system.multicall, permitiendo varias operaciones en una petición.
servidor.register_multicall_functions()
El batching reduce viajes de red, pero aumenta el trabajo por request. Limita número de llamadas, costo total y tamaño de respuesta. No agrupes operaciones destructivas sin atomicidad y comportamiento de fallo parcial definidos.
Tipos y allow_none
XML-RPC soporta tipos limitados. allow_none=True habilita una extensión para None que algunos clientes no implementan. use_builtin_types=True simplifica fechas y binarios.
Documenta tipos aceptados, límites, zona horaria de fechas, tamaño máximo de binarios y significado de valores ausentes. Para archivos grandes, usa un servicio de upload dedicado.
Faults y mensajes de error
Las excepciones de funciones registradas se convierten en faults XML-RPC. No devuelvas stack traces, rutas, SQL ni credenciales. Convierte fallos de dominio conocidos en códigos estables.
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, "usuario no encontrado")
return usuario
El mensaje todavía necesita escape cuando un cliente lo muestra en HTML.
Autenticación
SimpleXMLRPCServer no incluye una solución completa de autenticación moderna. Una arquitectura más segura lo coloca detrás de Nginx, Apache, API gateway o service mesh que valide mTLS, Basic Auth, tokens o identidad de workload.
Un request handler personalizado puede revisar headers, pero asegúrate de que las credenciales nunca lleguen a logs. Centraliza la política y prueba respuestas 401 y 403.
TLS
El servidor simple no ofrece una configuración HTTPS de producción especialmente cómoda. Termina TLS en un proxy reverso actualizado que gestione certificados, versiones, límites de cuerpo, timeouts y access logs.
Envolver el socket manualmente hace que tu aplicación sea responsable del handshake, shutdown y actualizaciones de seguridad. La guía de ssl en Python explica los riesgos.
Límite de cuerpo y XML malicioso
La advertencia de la documentación debe tomarse en serio. XML puede construirse para consumir memoria o CPU. Impone límite de Content-Length en el proxy, rechaza comportamientos no permitidos, configura timeouts y limita conexiones simultáneas.
No expongas el servidor a clientes anónimos. Segmentación de red y autenticación reducen el riesgo, pero no sustituyen límites de recursos.
Concurrencia
SimpleXMLRPCServer se basa en socketserver.TCPServer y procesa requests de forma síncrona. Un método lento bloquea los siguientes.
from socketserver import ThreadingMixIn
from xmlrpc.server import SimpleXMLRPCServer
class ServidorXMLRPCConThreads(ThreadingMixIn, SimpleXMLRPCServer):
daemon_threads = True
Los threads aumentan concurrencia, pero también carreras, consumo y sobrecarga. Protege estado compartido, limita conexiones y evita tareas largas. La guía de socketserver en Python detalla mixins y shutdown.
Timeouts y trabajos largos
No ejecutes informes extensos, procesamiento de vídeo o tareas indefinidas en el thread del request. Encola el trabajo, devuelve un identificador y ofrece un método de estado. Configura deadlines en proxy y cliente.
Apagado ordenado
Usa el servidor como context manager y llama shutdown() desde otro thread mientras serve_forever() está activo. Después cierra recursos de aplicación.
try:
servidor.serve_forever()
except KeyboardInterrupt:
pass
finally:
servidor.server_close()
En entornos gestionados, trata SIGTERM y deja de aceptar trabajo nuevo antes de terminar.
Logs
logRequests=True proporciona logs simples. En producción, usa eventos estructurados con método lógico, duración, resultado resumido e identificador de correlación. No registres cuerpos XML completos, tokens ni datos personales.
Documentación generada
DocXMLRPCServer puede servir una página HTML de documentación en requests GET. Es cómodo en laboratorio, pero puede revelar métodos y textos internos. No la expongas sin autenticación y revisión.
Cliente correspondiente
Consume el servicio con xmlrpc.client en Python. El cliente debe usar HTTPS, transporte con timeout, allowlist de métodos y tratamiento separado de Fault y ProtocolError.
Pruebas recomendadas
Prueba método válido e inexistente, parámetros fuera de rango, cuerpo demasiado grande, XML malformado, autenticación ausente, ruta incorrecta, llamadas simultáneas, multicall excesivo, shutdown y ausencia de secretos en faults y logs.
Ejecuta pruebas locales y nunca uses un servidor público de terceros para validar código destructivo.
Cuándo elegir otra tecnología
Para una API nueva, frameworks HTTP con JSON, schemas y middleware de seguridad suelen ser más adecuados. XML-RPC es útil principalmente para compatibilidad con sistemas existentes o herramientas internas simples en una red controlada.
Conclusión
xmlrpc.server permite crear rápidamente un endpoint RPC, pero la rapidez no elimina responsabilidades de seguridad. Registra funciones explícitamente, mantén allow_dotted_names desactivado, restringe rutas y payloads, autentica en un proxy, protege TLS, controla concurrencia y trata todo XML como no confiable.
Consulta la documentación oficial de xmlrpc.server y las orientaciones de seguridad XML de Python. Para servicios públicos o proyectos nuevos, considera una plataforma de API con controles más completos.







