You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在最新Golang版本的Go代码中获取TLS扩展(用于JA3)

在Go中获取TLS扩展以实现JA3功能

由于标准库的tls.ClientHelloInfo并未对外暴露扩展字段,你可以通过以下几种方式获取TLS ClientHello中的扩展数据:

1. 反射访问内部未导出字段

Go标准库的ClientHelloInfo结构体内部存在未导出的extensions字段(类型为map[uint16][]byte),可以通过反射读取。这种方式实现简单,但依赖标准库内部实现,未来版本可能失效:

import (
    "crypto/tls"
    "reflect"
)

func ExtractExtensions(chi *tls.ClientHelloInfo) map[uint16][]byte {
    chiVal := reflect.ValueOf(*chi)
    extField := chiVal.FieldByName("extensions")
    if !extField.IsValid() {
        return nil
    }
    return extField.Interface().(map[uint16][]byte)
}

2. 拦截并解析原始ClientHello字节流

更可靠的方式是在TLS握手阶段拦截原始的ClientHello数据,手动解析扩展字段。这种方式不依赖内部实现,稳定性更高:

实现步骤:

  • 包装net.Conn,读取并保存ClientHello的原始字节数据
  • 解析原始字节,按照TLS协议规范提取扩展字段
  • 结合解析出的字段生成JA3哈希

示例代码框架:

import (
    "bytes"
    "crypto/tls"
    "net"
)

type HelloCapturingConn struct {
    net.Conn
    helloBuffer *bytes.Buffer
}

func (c *HelloCapturingConn) Read(b []byte) (n int, err error) {
    n, err = c.Conn.Read(b)
    if n > 0 && c.helloBuffer.Len() == 0 {
        c.helloBuffer.Write(b[:n])
        // 此处需要补充完整的TLS记录层解析逻辑,确保获取完整的ClientHello消息
    }
    return
}

func ParseClientHelloExtensions(rawHello []byte) map[uint16][]byte {
    extensions := make(map[uint16][]byte)
    // 按照TLS协议规范解析ClientHello,跳过非扩展部分(握手类型、长度、版本、随机数等)
    // 遍历扩展列表,提取每个扩展的类型和数据
    // 具体解析逻辑可参考TLS RFC文档或成熟JA3库的实现
    return extensions
}

// 使用示例
func main() {
    tlsCfg := &tls.Config{
        GetConfigForClient: func(chi *tls.ClientHelloInfo) (*tls.Config, error) {
            if captureConn, ok := chi.Conn.(*HelloCapturingConn); ok {
                exts := ParseClientHelloExtensions(captureConn.helloBuffer.Bytes())
                // 基于exts和ClientHelloInfo中的其他字段生成JA3哈希
            }
            return tlsCfg, nil
        },
    }
    // 启动TLS服务时,将传入的Conn包装为HelloCapturingConn
}

3. 使用第三方JA3库

直接使用成熟的第三方库实现JA3功能,这些库已经封装了扩展解析和哈希生成逻辑,是生产环境的首选:

例如Cloudflare的JA3库:

import "github.com/cloudflare/ja3"

func processConn(conn net.Conn) {
    ja3Str, err := ja3.Compute(conn)
    if err != nil {
        // 处理错误
        return
    }
    // ja3Str即为生成的JA3字符串
}

内容的提问来源于stack exchange,提问作者unrealyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:33:20