TLS en 10 Minutos

TLS convierte una conversación de red legible en un canal cifrado y autenticado. Lo difícil rara vez es el cifrado. Es demostrar el hostname correcto, servir la cadena completa de certificados y renovar antes de que una fecha silenciosa se convierta en una caída.

🎙️ Publicado y grabado: ·

01HTTP plano expone más que contraseñas

HTTP plano no ofrece confidencialidad ni identidad de servidor confiable. Alguien en el camino puede leer peticiones, robar cookies de sesión, modificar JavaScript descargado o redirigir una llamada a la API. "Esta página no tiene formulario de contraseña" no es razón para mantener HTTP. Un script modificado puede esperar hasta que el usuario introduzca una contraseña en otro lugar.

# HTTP: readable and modifiable on the path
GET /account HTTP/1.1
Host: example.com
Cookie: session=secret-value

# HTTPS: HTTP travels inside a TLS-protected connection
https://example.com/account
Usa HTTPS en todas partes

Redirige el puerto ochenta a HTTPS, luego añade HSTS solo después de que cada subdominio necesario funcione sobre HTTPS. Las cookies que llevan sesiones necesitan Secure, HttpOnly y una política SameSite apropiada. TLS protege datos en tránsito. No repara una aplicación vulnerable, un endpoint malicioso ni una clave de servidor filtrada.

02El handshake TLS acuerda y autentica

Antes de que HTTP comience, el cliente ofrece versiones de protocolo, opciones criptográficas y el hostname que quiere. El servidor elige configuración compatible, envía su cadena de certificados y demuestra posesión de la clave privada correspondiente. El cliente valida la cadena y el hostname. Ambos lados derivan claves de sesión temporales y luego cifran los datos de la aplicación.

client                         server
  |--- ClientHello ------------>|  versions, cipher suites, SNI
  |<-- ServerHello -------------|  chosen parameters
  |<-- Certificate chain -------|  site cert + intermediates
  |<-- CertificateVerify -------|  proof of private key
  |--- Finished --------------->|
  |<-- Finished ----------------|
  |=== encrypted HTTP =========>|

El TLS moderno usa acuerdo de claves efímero, así que robar la clave del certificado después no debería descifrar sesiones antiguas capturadas. No elijas manualmente listas de cifrado exóticas de un blog antiguo. Usa la política TLS moderna de un servidor o plataforma mantenido, desactiva versiones de protocolo obsoletas y dedica tu atención a certificados, acceso a la clave privada y renovación.

03Un certificado vincula una clave a un hostname

Un certificado de sitio contiene una clave pública, ventana de validez, emisor y Subject Alternative Names. El hostname solicitado debe aparecer en esos nombres. El servidor normalmente envía su certificado hoja más los certificados intermedios. El cliente enlaza esa cadena a una raíz de confianza ya presente en su trust store. La raíz normalmente no debería ser enviada por el servidor.

# Inspect names, issuer, and dates from the live service
openssl s_client -connect example.com:443 -servername example.com \
  -showcerts </dev/null

# Inspect one saved certificate
openssl x509 -in cert.pem -noout -subject -issuer -dates \
  -ext subjectAltName
Hostname incorrecto, solucionado

Chrome muestra NET::ERR_CERT_COMMON_NAME_INVALID cuando el certificado no cubre el nombre solicitado. Uno: confirma la URL del navegador, incluyendo el subdominio. Dos: inspecciona los Subject Alternative Names con el comando anterior. Tres: emite un certificado que contenga ese hostname exacto. Cuatro: instálalo en el virtual host que sirve el nombre. Un wildcard para *.example.com cubre api.example.com, no example.com ni v2.api.example.com.

04SNI selecciona el certificado antes de HTTP

Una dirección IP a menudo aloja muchos sitios HTTPS. El servidor necesita elegir un certificado antes de poder leer el header HTTP Host cifrado. Server Name Indication resuelve eso poniendo el hostname solicitado en el ClientHello. Si SNI falta o el mapeo del servidor es incorrecto, puedes recibir el certificado del sitio por defecto.

# Correct: connect to the IP but send SNI for the hostname
openssl s_client -connect 203.0.113.10:443 \
  -servername api.example.com </dev/null

# Test the same routing with curl while preserving hostname
curl -v --resolve api.example.com:443:203.0.113.10 \
  https://api.example.com/health
No pruebes solo con la IP

Abrir https://203.0.113.10 pide un certificado válido para la IP y puede seleccionar el virtual host por defecto. Eso no reproduce la conexión de un usuario a api.example.com. Usa --resolve o -servername para que se omita DNS mientras el hostname real permanece en SNI y en la verificación del certificado.

05ACME automatiza la prueba y la emisión

ACME permite a una autoridad de certificación verificar que controlas un dominio y emitir un certificado de corta duración automáticamente. HTTP-01 coloca un token bajo una ruta HTTP well-known. DNS-01 publica un registro TXT y es necesario para certificados wildcard. TLS-ALPN-01 demuestra control mediante una respuesta TLS especial en el puerto cuatro-cuatro-tres.

# HTTP-01 must be publicly reachable at this exact path
http://example.com/.well-known/acme-challenge/TOKEN

# DNS-01 publishes a temporary TXT value
_acme-challenge.example.com.  TXT  "challenge-value"

# Check public DNS before blaming the ACME client
dig +short TXT _acme-challenge.example.com
Fallo en el challenge, solucionado

Un cliente puede reportar unauthorized: Invalid response from http://example.com/.well-known/acme-challenge/.... Uno: solicita la URL exacta del challenge desde fuera del servidor. Dos: confirma que DNS apunta a la máquina que responde al challenge. Tres: exime esa ruta de redirecciones de login y rewrites de la aplicación. Cuatro: permite el puerto ochenta entrante para HTTP-01, o cambia a DNS-01 con credenciales DNS de alcance limitado.

06Termina TLS en una frontera deliberada

Un reverse proxy a menudo posee el certificado público y reenvía peticiones a la aplicación. Eso centraliza la renovación y la configuración TLS moderna. La aplicación debe saber igualmente que la petición original fue HTTPS, y debe confiar en headers reenviados solo de proxies conocidos. Para tráfico a través de una red no confiable, cifra también el tramo proxy-a-app.

# Minimal nginx shape
server {
  listen 443 ssl http2;
  server_name example.com;
  ssl_certificate     /etc/ssl/example/fullchain.pem;
  ssl_certificate_key /etc/ssl/example/privkey.pem;

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}
El bucle de redirección

Si el navegador reporta ERR_TOO_MANY_REDIRECTS después de la terminación TLS, la app puede pensar que cada petición proxied llegó por HTTP. Uno: inspecciona X-Forwarded-Proto en la app. Dos: configúralo al scheme original en el proxy. Tres: configura la lista de proxies de confianza de la app, no un "confiar en todos" genérico. Cuatro: mantén exactamente un dueño de la redirección HTTP-a-HTTPS.

07mTLS autentica clientes con certificados

HTTPS ordinario autentica el servidor. Mutual TLS también pide al cliente un certificado, lo cual es útil para enlaces servicio-a-servicio, dispositivos y APIs de partners controlados. Es identidad de transporte fuerte, pero operacionalmente costosa. Debes emitir, rotar, revocar y mapear identidades de cliente sin bloquear a todos los llamantes a la vez.

# Call an mTLS endpoint
curl --cert client.crt --key client.key \
  --cacert service-ca.crt https://internal.example.com/health

# nginx client verification
ssl_client_certificate /etc/ssl/client-ca.pem;
ssl_verify_client on;
ssl_verify_depth 2;

No uses un certificado de cliente compartido para cien servicios. Dale a cada workload una identidad para que un compromiso pueda revocarse de forma acotada y los logs nombren al llamante. Mantén la autorización de la aplicación después de la verificación del certificado. Un certificado válido puede demostrar "servicio de inventario", pero la aplicación aún decide si ese servicio puede cancelar un pedido.

08Depura la cadena en vivo, el nombre y el reloj

Empieza con el hostname y puerto exactos que usa el cliente que falla. Inspecciona el servicio en vivo en lugar de un archivo de certificado que pretendías desplegar. Comprueba SNI, Subject Alternative Names, fechas de validez, los intermedios servidos y el reloj del cliente. Luego compara trust stores; un navegador y un contenedor pueden discrepar porque llevan certificados raíz diferentes.

# Fast HTTP and certificate trace
curl -Iv https://api.example.com/

# Verify what the server actually presents
openssl s_client -connect api.example.com:443 \
  -servername api.example.com -verify_return_error </dev/null

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]
certificate verify failed: unable to get local issuer certificate
Emisor faltante, solucionado

Para unable to get local issuer certificate, uno: ejecuta s_client -showcerts contra el host en vivo. Dos: verifica que el servidor envía el certificado hoja seguido del certificado intermedio requerido. Tres: instala el archivo full-chain de la CA en el terminador TLS y recárgalo. Cuatro: actualiza el bundle de CA del cliente si la cadena está completa pero su trust store está desactualizado. No envíes verify=False ni curl -k; esos switches eliminan la verificación de identidad que TLS debe proporcionar.

09La renovación es un flujo de trabajo de producción

La emisión automatizada no es suficiente. La renovación debe ejecutarse, instalar los nuevos archivos donde el proceso activo los lee y recargar ese proceso. Monitoriza el certificado observado desde fuera, no meramente un cron exit exitoso. Prueba la renovación mientras quedan meses. El primer fallo debería ser una alerta, no un screenshot de un cliente.

# Show expiry from the public endpoint
echo | openssl s_client -connect example.com:443 \
  -servername example.com 2>/dev/null \
  | openssl x509 -noout -enddate

# Generic post-renewal checks
acme-client renew
nginx -t && systemctl reload nginx
curl -fsS https://example.com/health
Certificado expirado, solucionado

Los clientes pueden mostrar certificate has expired. Uno: inspecciona la fecha notAfter del endpoint público y el reloj del servidor. Dos: renueva o reemite el certificado. Tres: despliega la nueva cadena completa y la clave en el terminador TLS real. Cuatro: recárgalo e inspecciona el endpoint público de nuevo. Cinco: alerta mucho antes de la expiración y alerta cuando el número de serie observado no cambie después de la renovación.

10TLS cheat sheet

Estos comandos responden la mayoría de preguntas de primera respuesta sin desactivar la verificación.

# inspect live TLS with correct SNI
openssl s_client -connect HOST:443 -servername HOST -showcerts
curl -Iv https://HOST/

# inspect certificate file
openssl x509 -in cert.pem -noout -subject -issuer -dates \
  -ext subjectAltName

# diagnose by symptom
wrong hostname → URL + SAN + SNI + virtual-host mapping
unknown issuer → served intermediates + client CA store
expired → public notAfter + renewal + reload
ACME failure → DNS + challenge path + reachable port

# rules worth keeping
serve leaf + intermediates · protect private key · automate renewal
monitor from outside · never use -k or verify=False in production

Mi versión directa: las librerías TLS normalmente no son tu problema. El despliegue sí. Sirve el certificado correcto para el nombre solicitado, incluye la cadena intermedia, automatiza la renovación y la recarga, y prueba el endpoint desde fuera de tu red. Cuando la verificación falla, corrige el nombre, la cadena, la fecha o el trust store. Desactivar la verificación convierte un error accionable en suplantación silenciosa.

Tell me what missed

A correction is more useful than a compliment. This goes straight to the person who writes SwiftGrasp.

Was this page useful?
0/1000

Please do not include passwords, private keys, or personal information.