ssl keylog_filename: analiza TLS en Wireshark

Publicado el: 02/10/2026
Tempo de leitura: 5 minutos
Pantalla de portátil con código para análisis TLS usando ssl keylog_filename en Python

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.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Portátil con código y base SQLite para sqlite3 autocommit en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    sqlite3 autocommit: controla transacciones en Python

    Aprende sqlite3 autocommit en Python para controlar transacciones, commits, rollbacks, compatibilidad y bloqueos de SQLite.

    Ler mais

    Tempo de leitura: 5 minutos
    02/10/2026
    Programador trabajando con objetos inmutables y copy.replace en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    copy.replace: actualiza objetos inmutables en Python

    Aprende copy.replace en Python para crear nuevas versiones de objetos con cambios puntuales, inmutabilidad y validación segura.

    Ler mais

    Tempo de leitura: 5 minutos
    01/10/2026
    Estructura de archivos y código para pathlib.Path.info en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pathlib.Path.info: caché de metadatos de archivos

    Aprende pathlib.Path.info en Python para clasificar archivos con metadatos en caché y optimizar recorridos de directorios.

    Ler mais

    Tempo de leitura: 5 minutos
    01/10/2026
    Portátil con material de pruebas en Python para loop_factory y asyncio
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    loop_factory: aísla event loops en pruebas asyncio

    Aprende loop_factory en IsolatedAsyncioTestCase para pruebas asyncio aisladas, predecibles y con limpieza segura.

    Ler mais

    Tempo de leitura: 5 minutos
    30/09/2026
    Desarrolladora navegando archivos ZIP con zipfile.Path en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    zipfile.Path: navega ZIPs sin extraer archivos

    Aprende zipfile.Path en Python para navegar, leer y validar archivos dentro de ZIPs sin extraer todo.

    Ler mais

    Tempo de leitura: 4 minutos
    30/09/2026
    Programador trabajando con encabezados de correo en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    email.headerregistry: headers de correo seguros

    Aprende email.headerregistry en Python para encabezados, direcciones, grupos, fechas, parámetros y análisis seguro de correos.

    Ler mais

    Tempo de leitura: 5 minutos
    29/09/2026