Pular para o conteúdo
ecdsa.com
Go crypto/tlsGo

Mensagem de erro

tls: first record does not look like a TLS handshake

O gRPC, drivers de banco de dados e outras bibliotecas encapsulam o erro nas próprias mensagens, então procure nos logs o trecho central do texto. Para respostas HTTP, o net/http diz “http: server gave HTTP response to HTTPS client” em vez disso.

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

O que significa

O cliente TLS do Go enviou um ClientHello, e o primeiro registro que recebeu de volta não tem a estrutura de um registro de handshake TLS, então ele desiste imediatamente. O outro lado fala outra coisa nessa porta: HTTP não criptografado (quando o Go não consegue reconhecê-lo como tal), um servidor gRPC não criptografado, a saudação de um protocolo de banco de dados ou de e-mail. Servidores Go registram de outra forma a situação inversa, um cliente que fala texto claro com uma porta TLS.

Por que acontece

Como corrigir

  1. 1.

    Verificar o que a porta fala

    Um handshake TLS com o openssl, ou uma olhada rápida no banner, mostra se a porta usa TLS ou não.

    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 as credenciais que o servidor espera

    Credenciais TLS para servidores TLS; credenciais inseguras só para servidores não criptografados em redes confiáveis.

    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 onde o protocolo exige

    O StartTLS do net/smtp (e os equivalentes nos drivers de banco de dados, por exemplo, o sslmode do PostgreSQL) passa a conexão para TLS dentro do próprio 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"})
    }

Erros relacionados

Ver toda a base de erros de assinatura