Golang中SSL/HTTPS异常:首个记录不符合TLS握手协议的问题解决

Golang中SSL/HTTPS异常:首个记录不符合TLS握手协议的问题解决 我正在使用以下代码提供HTTPS服务,一切运行正常,客户端能正常访问页面,没有SSL错误,所有功能都正常工作,也没有生成日志,但是几乎每秒都会出现"first record does not look like a tls handshake"这条消息,这条消息被打印了数百次。以下是我使用的代码:

	err := http.ListenAndServeTLS(":81", PastaCertSSL+"hlsatsslcrt.pem", PastaCertSSL+"server.key", nil)
	if err != nil {
		GeraLog(err.Error())
	}

客户端使用正确的URL进行访问:

https://sub.mydomain.tld:81/

有人知道如何解决这个问题吗?


更多关于Golang中SSL/HTTPS异常:首个记录不符合TLS握手协议的问题解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

我指的是我的客户,抱歉。

更多关于Golang中SSL/HTTPS异常:首个记录不符合TLS握手协议的问题解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你所说的客户端是指什么?是网页浏览器还是其他什么?

你确定他们的 HTTP 客户端真的使用了 TLS 吗?

这意味着有人连接并尝试使用非TLS协议进行通信。可能您的图片链接使用了普通的HTTP协议,或存在类似情况。

这是一个 REST API,没有图像也没有 HTML 内容,它只是一个向输出写入 JSON 的 REST API……

我找到了问题的症结所在。这个 REST API 为 Android 应用提供数据,部分设备版本过旧,仍尝试连接旧的 HTTP 网址。由于新旧网址相同且端口一致,唯一的区别在于 HTTPS,这些设备最终连接到了新的 TLS 服务,因此出现了握手警告。感谢各位。

这是一个典型的TLS握手异常问题,通常发生在非TLS客户端尝试连接到HTTPS端口时。最常见的原因是端口扫描、爬虫或错误配置的客户端发送了非TLS流量到你的HTTPS端口。

以下是几种解决方案:

方案1:添加TLS配置和连接过滤

import (
    "crypto/tls"
    "net"
    "net/http"
    "time"
)

func main() {
    // 创建自定义TLS配置
    tlsConfig := &tls.Config{
        MinVersion:               tls.VersionTLS12,
        PreferServerCipherSuites: true,
        CipherSuites: []uint16{
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
        },
    }

    // 创建自定义服务器
    server := &http.Server{
        Addr:      ":81",
        TLSConfig: tlsConfig,
    }

    // 使用自定义监听器
    ln, err := net.Listen("tcp", ":81")
    if err != nil {
        GeraLog(err.Error())
        return
    }

    // 包装为TLS监听器
    tlsListener := tls.NewListener(ln, tlsConfig)
    
    err = server.Serve(tlsListener)
    if err != nil {
        GeraLog(err.Error())
    }
}

方案2:实现连接嗅探和过滤

import (
    "bufio"
    "crypto/tls"
    "net"
    "net/http"
    "strings"
    "time"
)

type tlsSniffConn struct {
    net.Conn
    r *bufio.Reader
}

func (c *tlsSniffConn) Read(b []byte) (int, error) {
    return c.r.Read(b)
}

func main() {
    ln, err := net.Listen("tcp", ":81")
    if err != nil {
        GeraLog(err.Error())
        return
    }

    for {
        conn, err := ln.Accept()
        if err != nil {
            GeraLog("Accept error: " + err.Error())
            continue
        }

        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
    // 设置读取超时
    conn.SetReadDeadline(time.Now().Add(5 * time.Second))
    
    // 创建带缓冲的读取器来嗅探第一个数据包
    r := bufio.NewReader(conn)
    peek, err := r.Peek(1)
    if err != nil {
        conn.Close()
        return
    }

    // 重置读取超时
    conn.SetReadDeadline(time.Time{})

    // 检查是否是TLS握手(TLS握手通常以0x16开头)
    if len(peek) > 0 && peek[0] == 0x16 {
        // 是TLS流量,进行TLS握手
        tlsConn := tls.Server(&tlsSniffConn{conn, r}, &tls.Config{
            Certificates: []tls.Certificate{loadCertificate()},
        })
        
        // 创建HTTP服务器处理TLS连接
        http.Serve(tlsConn, nil)
    } else {
        // 非TLS流量,直接关闭连接
        conn.Close()
    }
}

func loadCertificate() tls.Certificate {
    cert, err := tls.LoadX509KeyPair(PastaCertSSL+"hlsatsslcrt.pem", PastaCertSSL+"server.key")
    if err != nil {
        GeraLog("Certificate load error: " + err.Error())
    }
    return cert
}

方案3:使用更严格的TLS配置

func main() {
    tlsConfig := &tls.Config{
        MinVersion:   tls.VersionTLS12,
        MaxVersion:   tls.VersionTLS13,
        CipherSuites: []uint16{
            tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
            tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
        },
        // 拒绝不完整的TLS握手
        VerifyConnection: func(cs tls.ConnectionState) error {
            if !cs.HandshakeComplete {
                return tls.CertificateVerificationError{Err: errors.New("incomplete handshake")}
            }
            return nil
        },
    }

    server := &http.Server{
        Addr:      ":81",
        TLSConfig: tlsConfig,
        // 设置更短的读写超时
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    err := server.ListenAndServeTLS(PastaCertSSL+"hlsatsslcrt.pem", PastaCertSSL+"server.key")
    if err != nil {
        GeraLog(err.Error())
    }
}

这些方案通过过滤非TLS流量、加强TLS配置和设置适当的超时来减少"first record does not look like a tls handshake"警告的出现频率。方案2的连接嗅探方法能最有效地阻止非TLS流量到达TLS层。

回到顶部