Depurar HTTPS es complicado porque TLS oculta precisamente los datos que un desarrollador necesita observar. El atributo SSLContext.keylog_filename de Python permite registrar secretos de sesión en el formato NSS Key Log. Wireshark puede combinar esos secretos con una captura de paquetes y descifrar sesiones TLS autorizadas.
La función no convierte HTTPS en HTTP, no desactiva la validación de certificados y no modifica el tráfico enviado. Los paquetes siguen cifrados. Solo quien posee la captura y el archivo de claves correspondiente puede interpretar la sesión. Por eso resulta útil en desarrollo, pruebas de integración, análisis de APIs, diagnóstico de incompatibilidades TLS e investigación de errores de protocolo.
Qué hace keylog_filename
keylog_filename pertenece a ssl.SSLContext. Al asignar una ruta escribible antes del handshake, Python añade los secretos TLS al archivo. Según la versión negociada, aparecen registros CLIENT_RANDOM o etiquetas específicas de TLS 1.3.
La disponibilidad depende de la biblioteca OpenSSL usada por la instalación de Python. Las versiones modernas suelen admitirla en Linux, macOS y Windows, pero conviene verificar el entorno real antes de depender de ella.
Ejemplo básico con urllib
import ssl
import urllib.request
contexto = ssl.create_default_context()
contexto.keylog_filename = "tls-keys.log"
with urllib.request.urlopen(
"https://www.python.org/",
context=contexto,
timeout=10,
) as respuesta:
print(respuesta.status)
print(respuesta.read(200))
El contexto predeterminado mantiene activa la validación del certificado y del nombre del servidor. La única conducta adicional es guardar los secretos de la sesión. Inicia la captura antes de ejecutar el script y configura Wireshark para leer el archivo generado.
Configurar Wireshark
Abre las preferencias de Wireshark, busca la configuración del protocolo TLS e introduce la ruta absoluta del archivo. Luego recarga la captura o inicia una nueva. Los filtros tls, http2 y http ayudan a localizar el contenido descifrado.
La documentación oficial de ssl describe el contexto y sus propiedades. La guía TLS de Wireshark explica el uso del archivo de claves y las limitaciones de captura.
Ejemplo con sockets
import socket
import ssl
contexto = ssl.create_default_context()
contexto.keylog_filename = "secretos-tls.log"
with socket.create_connection(("www.python.org", 443), timeout=10) as bruto:
with contexto.wrap_socket(bruto, server_hostname="www.python.org") as seguro:
seguro.sendall(
b"GET / HTTP/1.1\r\nHost: www.python.org\r\nConnection: close\r\n\r\n"
)
datos = seguro.recv(4096)
print(datos.decode("latin-1", errors="replace"))
La propiedad debe configurarse antes de que wrap_socket complete el handshake. Activarla después no recupera secretos de una sesión ya negociada.
Variable SSLKEYLOGFILE
Algunas aplicaciones respetan la variable de entorno SSLKEYLOGFILE. En situaciones compatibles, los contextos predeterminados de Python también pueden aprovecharla. Sin embargo, una asignación explícita suele ser más clara en pruebas porque documenta la intención y evita depender del estado global.
export SSLKEYLOGFILE="$PWD/tls-keys.log"
python cliente.py
Para archivos de diagnóstico temporales, utiliza una carpeta protegida y elimina el archivo al finalizar. El artículo de Academify sobre tempfile en Python explica el ciclo de vida de archivos temporales, y la guía de pathlib en Python ayuda a gestionar rutas.
El archivo es un secreto
Un key log TLS es muy sensible. Quien obtiene la captura y el archivo correspondiente puede descifrar las sesiones registradas. Nunca lo subas a Git, no lo adjuntes a incidencias públicas y no lo envíes a servicios de soporte sin protección. Añade patrones como *.keylog y tls-keys.log a .gitignore.
Evita activar la función en producción. Un servicio de larga duración puede generar un archivo grande con secretos de muchos usuarios. Esto introduce riesgos de exposición, retención, espacio en disco y concurrencia. Limita los permisos al usuario del proceso y reduce al mínimo la ventana de diagnóstico.
Función auxiliar segura
from pathlib import Path
import ssl
def crear_contexto_debug(ruta: Path, activo: bool = False) -> ssl.SSLContext:
contexto = ssl.create_default_context()
if activo:
ruta.parent.mkdir(parents=True, exist_ok=True)
contexto.keylog_filename = str(ruta)
return contexto
contexto = crear_contexto_debug(
Path(".debug") / "tls-keys.log",
activo=True,
)
Una opción explícita reduce activaciones accidentales. En aplicaciones grandes, vincula la opción a una configuración local y recházala durante el arranque en producción.
Uso con httpx
import ssl
import httpx
contexto = ssl.create_default_context()
contexto.keylog_filename = "httpx-tls.log"
with httpx.Client(verify=contexto, timeout=10) as cliente:
respuesta = cliente.get("https://www.python.org/")
print(respuesta.status_code)
Algunos clientes HTTP aceptan un SSLContext directamente; otros requieren un transporte o adaptador personalizado. Consulta las guías de Academify sobre urllib.request y requests en Python para separar errores de aplicación, DNS, TCP, certificados y protocolo.
Problemas frecuentes
Un archivo vacío suele indicar que la ruta no permite escritura, no ocurrió un nuevo handshake o el pool reutilizó una conexión existente. Cierra el cliente, fuerza una conexión nueva y repite la captura. Otra causa habitual es capturar la interfaz de red incorrecta, sobre todo con contenedores, VPN, máquinas virtuales o WSL.
Un archivo antiguo no descifra sesiones nuevas. Del mismo modo, un archivo nuevo no permite descifrar una captura anterior si los secretos correspondientes nunca se registraron. La captura y el key log deben pertenecer a los mismos handshakes.
TLS 1.3 y HTTP/2
TLS 1.3 utiliza varios secretos de tráfico. El formato NSS los representa con etiquetas específicas que Wireshark moderno entiende. Después de descifrar TLS, Wireshark todavía debe interpretar el protocolo de aplicación. Muchas APIs HTTPS negocian HTTP/2 mediante ALPN, por lo que el contenido aparece como frames HTTP/2 y no como texto HTTP/1.1.
Uso responsable
Utiliza esta capacidad solo en sistemas, cuentas y redes para los que tengas autorización. Es adecuada para servicios propios, pruebas, staging y respuesta a incidentes aprobada. No debe emplearse para interceptar tráfico ajeno, recopilar credenciales o evitar controles de seguridad.
Lista de comprobación
- Mantén la validación de certificados activa.
- Define la ruta antes del handshake.
- Usa una ruta absoluta en Wireshark.
- Captura la interfaz correcta.
- Fuerza una conexión nueva si es necesario.
- Protege el archivo con permisos restrictivos.
- Elimina el log después del diagnóstico.
- No lo subas al control de versiones.
Conclusión
SSLContext.keylog_filename es una herramienta eficaz para diagnosticar TLS desde Python. Mantiene el cifrado y la validación normales, pero proporciona a Wireshark los secretos necesarios para analizar una captura coincidente. Con un contexto dedicado, permisos estrictos y una ventana breve de uso, permite observar cabeceras HTTP, redirecciones, negociación ALPN, frames HTTP/2 y comportamientos de APIs que de otro modo permanecerían ocultos.







