Cómo funcionan realmente HTTPS y TLS: handshake y certificados

Security2026-10-27TryQuickToolBox

Añades un certificado SSL, apuntas tu dominio a un servidor y aparece el candado. La mayoría de los desarrolladores se detienen ahí. Hasta que un día un cliente API falla con UNABLE_TO_VERIFY_LEAF_SIGNATURE, una aplicación móvil rechaza tu certificado en Android antiguo, o un balanceador de carga termina TLS y tu aplicación ve todo como HTTP plano. De repente necesitas saber qué ocurre realmente entre la conexión TCP y la primera petición HTTP.

Este artículo recorre cómo funcionan realmente HTTPS y TLS: qué hace el handshake, cómo se validan los certificados, qué cambió en TLS 1.3 y cómo diagnosticar los errores que realmente encontrarás.

Qué añade realmente HTTPS

HTTPS es HTTP enviado sobre una conexión TLS. TLS proporciona tres garantías:

Fíjate en lo que no está en esa lista: el cliente no se autentica por defecto. TLS autentica al servidor; tu aplicación autentica al usuario.

El handshake TLS 1.2, paso a paso

TLS 1.2 sigue siendo común en infraestructuras antiguas y en muchos proxies corporativos, así que vale la pena entenderlo. Un handshake completo se ve así:

  1. ClientHello — el cliente envía las versiones de TLS soportadas, un valor aleatorio, una lista de suites de cifrado y (si aplica) el nombre de host SNI.
  2. ServerHello — el servidor elige una versión y una suite de cifrado, devuelve su propio valor aleatorio y envía su cadena de certificados.
  3. Intercambio de claves — con ECDHE, el servidor envía una clave pública efímera; el cliente envía la suya. Ambos derivan el mismo secreto compartido. El servidor firma la transcripción del handshake con la clave privada de su certificado.
  4. Finished — ambas partes envían un MAC sobre la transcripción del handshake, confirmando que nada fue manipulado.
  5. Datos de aplicación — las peticiones y respuestas HTTP fluyen cifradas.

El detalle crítico es el intercambio de claves efímero. Con ECDHE, se genera un nuevo par de claves por conexión. Incluso si un atacante graba años de tráfico y luego roba la clave privada del servidor, no puede descifrar sesiones pasadas. Esa propiedad se llama secreto hacia adelante (forward secrecy) y es la razón principal por la que el intercambio de claves RSA estático ha quedado obsoleto.

Cómo cambió el juego TLS 1.3

TLS 1.3 simplifica el handshake a un solo viaje de ida y vuelta y elimina por completo los algoritmos heredados.

AspectoTLS 1.2TLS 1.3
Viajes de ida y vuelta (handshake completo)21
Intercambio de clavesRSA o ECDHESolo ECDHE (secreto hacia adelante)
Suites de cifradoCifrado, MAC e intercambio de claves por separadoSolo suites AEAD, p. ej. TLS_AES_128_GCM_SHA256
RSA estático, CBC, RC4PermitidoEliminado
Reanudación de sesiónIDs de sesión / ticketsPSK con opción 0-RTT

En TLS 1.3, el cliente adivina el grupo de intercambio de claves y envía su parte en el primer mensaje, de modo que el servidor puede completar el acuerdo de claves de inmediato. Los certificados todavía se envían, pero ahora van cifrados, lo que significa que los observadores pasivos ya no pueden ver qué nombre de host se está sirviendo — solo el SNI en el ClientHello lo filtra, a menos que se use Encrypted Client Hello.

La reanudación 0-RTT permite que un cliente que regresa envíe datos de aplicación con el primer vuelo. Es rápido, pero los datos 0-RTT son rejugables, así que nunca los uses para peticiones no idempotentes como pagos.

Certificados y validación de la cadena

Un certificado vincula una clave pública a un nombre de host. La validación es un recorrido de la cadena:

La causa más común de errores unable to verify es un certificado intermedio faltante. Los navegadores a veces lo disimulan almacenando en caché los intermedios, pero las herramientas de línea de comandos y las aplicaciones móviles fallan sin remedio. Sirve siempre la cadena completa, primero la hoja, luego los intermedios — nunca la raíz.

Depuración práctica con OpenSSL

Cuando algo falla, inspecciona lo que el servidor envía realmente antes de culpar al cliente.

# Mostrar la cadena de certificados que presenta el servidor
openssl s_client -connect example.com:443 -servername example.com -showcerts

# Negociar solo TLS 1.3 y listar el cifrado elegido
openssl s_client -connect example.com:443 -tls1_3

# Comprobar la caducidad del certificado en una línea
echo | openssl s_client -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates -subject -ext subjectAltName

Si s_client informa verify error:num=21:unable to verify the first certificate, la cadena está incompleta. Si informa un desajuste de nombre de host, revisa la lista SAN — los certificados comodín cubren solo una etiqueta, así que *.example.com coincide con api.example.com pero no con a.b.example.com.

Errores de configuración comunes

Una configuración de servidor razonable

Para Nginx, una base moderna se ve así:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;

Deja que el servidor elija los cifrados en TLS 1.3 — la preferencia del cliente está bien ahí porque todas las suites son fuertes. Mantén los tickets de sesión desactivados a menos que rotes las claves de ticket, ya que una clave de ticket filtrada puede comprometer la reanudación.

Preguntas frecuentes

¿HTTPS cifra el nombre de host?

No por defecto. La extensión SNI en el ClientHello se envía en texto plano para que el servidor sepa qué certificado presentar. Encrypted Client Hello (ECH) lo oculta, pero su adopción aún es limitada. La ruta y la cadena de consulta siempre van cifradas.

¿Por qué mi certificado funciona en un navegador pero falla en curl o en una aplicación móvil?

Casi siempre es un certificado intermedio faltante. Los navegadores a menudo obtienen o almacenan en caché los intermedios por su cuenta, mientras que los clientes más estrictos requieren que el servidor envíe la cadena completa. Verifícalo con openssl s_client -showcerts.

¿TLS 1.3 es siempre más rápido que TLS 1.2?

Para conexiones nuevas, sí — un viaje de ida y vuelta en lugar de dos. Para conexiones reanudadas la diferencia se reduce, y 0-RTT puede hacer TLS 1.3 aún más rápido, a costa del riesgo de repetición en peticiones no idempotentes.

Si estás auditando un servidor web tras un cambio de TLS, el análisis de logs a menudo revela el impacto real: redirecciones rotas, picos inesperados de 4xx o clientes que siguen accediendo por HTTP. Puedes cargar un log de acceso en el analizador de logs de Nginx para ver la distribución de códigos de estado y detectar clientes que nunca completaron la actualización a HTTPS.