Saltar al contenido
ecdsa.com
Go crypto/tlsGo

Mensaje de error

tls: first record does not look like a TLS handshake

gRPC, los controladores de bases de datos y otras bibliotecas lo envuelven en sus propios mensajes, así que busca en los registros el texto central. Ante respuestas HTTP, net/http dice en cambio «http: server gave HTTP response to HTTPS client».

Go crypto/tls — the peer's first bytes are not a TLS record (tls.Dial, gRPC, database drivers, http.Client)

Qué significa

El cliente TLS de Go envía un ClientHello y el primer registro TLS que recibe de vuelta no tiene la estructura de un registro de handshake, así que abandona de inmediato. El otro extremo habla otra cosa en ese puerto: HTTP plano (cuando Go no puede reconocerlo como tal), un servidor gRPC en texto plano o el saludo inicial de un protocolo de base de datos o de correo. En los servidores Go, la situación inversa (un cliente que habla texto plano a un puerto TLS) queda registrada con otro mensaje.

Por qué ocurre

Cómo solucionarlo

  1. 1.

    Comprobar qué habla el puerto

    Un handshake TLS con openssl, o un vistazo rápido al banner, muestra si el puerto usa TLS o no.

    bash
    # Does the port speak TLS?
    openssl s_client -connect api.example.com:8080 -servername api.example.com -brief </dev/null
    timeout 3 nc api.example.com 8080 </dev/null | head -1     # a text banner = plain protocol
  2. 2.

    gRPC: usar las credenciales que espera el servidor

    Credenciales TLS para servidores TLS; credenciales inseguras solo para servidores en texto plano en redes de confianza.

    go
    // gRPC: match the server. Plaintext server -> insecure credentials (only on trusted networks);
    // TLS server -> TLS credentials.
    conn, err := grpc.NewClient("api.example.com:9090",
    	grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ServerName: "api.example.com"})))
  3. 3.

    Usar STARTTLS donde el protocolo lo exija

    StartTLS de net/smtp (y sus equivalentes en los controladores de bases de datos, por ejemplo sslmode en PostgreSQL) pasa la conexión a TLS dentro del mismo canal.

    go
    // SMTP on 587 starts in plain text: use STARTTLS, not tls.Dial
    c, err := smtp.Dial("mail.example.com:587")
    if err == nil {
    	err = c.StartTLS(&tls.Config{ServerName: "mail.example.com"})
    }

Errores relacionados

Explorar toda la base de datos de errores de firma