Rumah >pembangunan bahagian belakang >Golang >Bina cap jari JA3 anda sendiri dengan Go

Bina cap jari JA3 anda sendiri dengan Go

Go语言进阶学习
Go语言进阶学习ke hadapan
2023-07-24 16:20:53873semak imbas
Dalam artikel ini, kami akan menyemak secara ringkas proses jabat tangan https, dan menerangkan apa itu cap jari JA3 dan cara menyesuaikan cap jari JA3 eksklusif dengan Go berdasarkan soalan yang dibangkitkan oleh pembaca.
Bina cap jari JA3 anda sendiri dengan Go

Garis besar artikel ini adalah seperti berikut. Sila ikuti idea Lao Xu dan bina cap jari JA3 anda sendiri secara beransur-ansur.

Bina cap jari JA3 anda sendiri dengan Go

Semak proses jabat tangan HTTPS

Sebelum kami mula memahami secara rasmi apa itu cap jari JA3, kami semak dahulu proses jabat tangan HTTPS, yang akan membantu memahami perkara berikut.

Saya telah mengekodkan lebih daripada 2,000 baris kod hanya untuk menjelaskan proses jabat tangan TLS Artikel ini terutamanya menganalisis proses pengesahan sehala dan pengesahan dua hala HTTPS (TLS1.3).

Dalam Pengesahan sehala, pelanggan tidak memerlukan sijil, ia hanya perlu mengesahkan bahawa sijil pelayan itu sah. Proses berjabat tangan dan pertukaran msg adalah seperti berikut.

Bina cap jari JA3 anda sendiri dengan Go

Dalam pengesahan dua hala, kedua-dua pelayan dan pelanggan perlu mengesahkan kesahihan sijil pihak yang satu lagi. Proses berjabat tangan dan pertukaran msg adalah seperti berikut.

Bina cap jari JA3 anda sendiri dengan Go

Perbandingan pengesahan sehala dan pengesahan dua hala:

  1. Dalam pengesahan sehala dan pengesahan dua hala, jumlah data dihantar dan diterima hanya tiga kali, dan data yang dihantar dalam satu masa mengandungi satu atau lebih mesej

  2. clientHelloMsg dan serverHelloMsgTidak disulitkan, semua mesej yang dihantar selepas itu disulitkanclientHelloMsgserverHelloMsg未经过加密,之后发送的消息均做了加密处理

  3. Client和Server会各自计算两次密钥,计算时机分别是读取到对方的HelloMsgfinishedMsg之后

  4. 双向认证和单向认证相比,服务端多发送了certificateRequestMsgTLS13消息

  5. 双向认证和单向认证相比,客户端多发送了certificateMsgTLS13certificateVerifyMsg

    🎜🎜🎜🎜Pelanggan dan Pelayan masing-masing akan mengira kunci dua kali, dan pemasaan pengiraan adalah masing-masing Baca HelloMsg dan finishedMsgSelepas 🎜🎜🎜🎜🎜🎜Berbanding dengan pengesahan sehala, pelayan menghantar lebih banyak certificateRequestMsgTLS13 mesej 🎜🎜🎜🎜🎜🎜Berbanding dengan pengesahan sehala, pelanggan menghantar lebih banyak certificateMsgTLS13andcertificateVerifyMsgdua mesej 🎜

Sama ada pengesahan sehala atau pengesahan dua hala, pemahaman Pelayan tentang maklumat asas Klien bergantung sepenuhnya pada Klien secara aktif memberitahu Pelayan, dan maklumat yang lebih kritikal adalah 客户端支持的TLS版本客户端支持的加密套件(cipherSuites)客户端支持的签名算法和客户端支持的密钥交换协议以及其对应的公钥。这些信息均在包含clientHelloMsg中,而这些信息也是生成JA3指纹的关键信息,并且clientHelloMsgserverHelloMsgtidak disulitkan. Tidak disulitkan bermakna kesukaran pengubahsuaian dikurangkan, yang juga memberikan kemungkinan untuk kami menyesuaikan cap jari JA3 kami sendiri.

"

Jika anda berminat untuk mengetahui butiran lanjut tentang proses jabat tangan HTTPS, sila baca artikel berikut:

Kod lebih daripada 2,000 baris kod hanya untuk menjelaskannya.

Kod lebih daripada 2,000 baris kod hanya untuk menjelaskannya. Menurut artikel Open Sourcing JA3, Lao Xu hanya memahaminya sebagai JA3 ialah kaedah pengenalan dalam talian cap jari pelanggan TLS.

该方法用于收集clientHelloMsg数据包中以下字段的十进制字节值:Versi TLSSifir DiterimaSenarai SambunganEliptik CurvesFormat Lengkung Eliptik。然后,它将这些值串联起来,使用“,”来分隔吗中吗中吗中中文-”来分隔各个字段中的值。最后,计算这些字符串的md5哈希值,即得到易于使得到易于使得到易于使用和的3于使用和的3于使用和指纹。clientHelloMsg数据包中以下字段的十进制字节值:TLS VersionAccepted CiphersList of ExtensionsElliptic CurvesElliptic Curve Formats。然后,它将这些值串联起来,使用“,”来分隔各个字段,同时使用“-”来分隔各个字段中的值。最后,计算这些字符串的md5哈希值,即得到易于使用和共享的长度为32字符的指纹。

为了更近一步描述清楚这些数据的来源,老许将John Althouse文章中的抓包图结合Go源码中的clientHelloMsg

为了更近一步描述清楚这些数据的来源,老许将John Althouse文章中的抓包图结合Go源码中的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px; margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: " operator mono consolas monaco menlo monospace break-all rgb>clientHelloMsg结构体做了字段一一映射。
Bina cap jari JA3 anda sendiri dengan Go

细心的同学南段一一映射。

细心的同学可管前文描述JA3指纹总共有5个数据字段,而上图却只映射了4个。那是因为 TLS的extension字段比较多,老许就不一一整理了。虽然沗一一虽然没了准备了一个单元测试,有兴趣深入研究的同学可以通过这个单元测试进行调试分析。

https://github.com/Isites/go-coder/blob/master/http2/tls/handsh/msg_test.go

🎜🎜JA3指纹用途🎜🎜🎜根据公是根据前一个md5字符串。请大家回想一下在平时的开发中md5的用途。🎜
  • 判断内容是否一致
  • 作为唯一标识

md5虽然不安全,但是JA3选择md5作为哈希的主要原因是为了更好的向后兼容

很明显,JA3指纹也有其类似用途。举个简单的例子,攻击者构建了一个可执行文件,那么该文件的JA3指纹很有可能是唯一的。因此,我们能通过JA3指纹识别出一些恶意软件。

在本小节的最后,老许给大家推荐一个网站,该网站挂出了很多恶意JA3指纹列表。

https://sslbl.abuse.ch/ja3-fingerprints/

构建专属的JA3指纹

http1.1的专属指纹

前文提到clientHelloMsgserverHelloMsg未经过加密,这为定制自己专属的JA3指纹提供了可能,而在github上面有一个库(https://github.com/refraction-networking/utls)可以在一定程度上修改clientHelloMsg。下面我们将通过这个库构建一个自己专属的JA3指纹。

// 关键import
import (
    xtls "github.com/refraction-networking/utls"
    "crypto/tls"
)

// 克隆一个Transport
tr := http.DefaultTransport.(*http.Transport).Clone()
// 自定义DialTLSContext函数,此函数会用于创建tcp连接和tls握手

tr.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
 dialer := net.Dialer{}
 // 创建tcp连接
 con, err := dialer.DialContext(ctx, network, addr)
 if err != nil {
  return nil, err
 }
 // 根据地址获取host信息
 host, _, err := net.SplitHostPort(addr)
 if err != nil {
  return nil, err
 }
 // 构建tlsconf
 xtlsConf := &xtls.Config{
  ServerName:    host,
  Renegotiation: xtls.RenegotiateNever,
 }
 // 构建tls.UConn
 xtlsConn := xtls.UClient(con, xtlsConf, xtls.HelloCustom)
 clientHelloSpec := &xtls.ClientHelloSpec{
     // hellomsg中的最大最小tls版本
  TLSVersMax: tls.VersionTLS12,
  TLSVersMin: tls.VersionTLS10,
  // ja3指纹需要的CipherSuites
  CipherSuites: []uint16{
   tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
   tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
   // tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
   tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
   tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
   tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
   tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
   tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   // tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
   tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
   tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
   tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
   tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
  },
  CompressionMethods: []byte{
   0,
  },
  // ja3指纹需要的Extensions
  Extensions: []xtls.TLSExtension{
   &xtls.RenegotiationInfoExtension{Renegotiation: xtls.RenegotiateOnceAsClient},
   &xtls.SNIExtension{ServerName: host},
   &xtls.UtlsExtendedMasterSecretExtension{},
   &xtls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []xtls.SignatureScheme{
    xtls.ECDSAWithP256AndSHA256,
    xtls.PSSWithSHA256,
    xtls.PKCS1WithSHA256,
    xtls.ECDSAWithP384AndSHA384,
    xtls.ECDSAWithSHA1,
    xtls.PSSWithSHA384,
    xtls.PSSWithSHA384,
    xtls.PKCS1WithSHA384,
    xtls.PSSWithSHA512,
    xtls.PKCS1WithSHA512,
    xtls.PKCS1WithSHA1}},
   &xtls.StatusRequestExtension{},
   &xtls.NPNExtension{},
   &xtls.SCTExtension{},
   &xtls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
   // ja3指纹需要的Elliptic Curve Formats
   &xtls.SupportedPointsExtension{SupportedPoints: []byte{1}}, // uncompressed
   // ja3指纹需要的Elliptic Curves
   &xtls.SupportedCurvesExtension{
    Curves: []xtls.CurveID{
     xtls.X25519,
     xtls.CurveP256,
     xtls.CurveP384,
     xtls.CurveP521,
    },
   },
  },
 }
 // 定义hellomsg的加密套件等信息
 err = xtlsConn.ApplyPreset(clientHelloSpec)
 if err != nil {
  return nil, err
 }
 // TLS握手
 err = xtlsConn.Handshake()
 if err != nil {
  return nil, err
 }
 fmt.Println("当前请求使用协议:", xtlsConn.HandshakeState.ServerHello.AlpnProtocol)
 return xtlsConn, err
}

上述代码总结起来分为三步。

  1. 创建TCP连接

  2. 构建clientHelloMsg需要的信息

  3. 完成TLS握手

有了上述代码后,我们通过请求https://ja3er.com/json来得到自己的JA3指纹。

c := http.Client{
 Transport: tr,
}
resp, err := c.Get("https://ja3er.com/json")
if err != nil {
 fmt.Println(err)
 return
}
bts, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
fmt.Println(string(bts), err)

最后得到的JA3指纹如下。

Bina cap jari JA3 anda sendiri dengan Go

我们已经得到了第一个JA3指纹,这个时候对代码稍加改动以期得到专属的JA3指纹。例如我们将2333这个数值加入到CipherSuites列表中,最后得到结果如下。

Bina cap jari JA3 anda sendiri dengan Go

最终,JA3指纹又发生了变化,并且可称得上是自己专属的指纹。不用我说,看标题就应该知道问题还没有结束。从前面请求得到JA3指纹的结果图也可以看出来,当前使用的协议为http1.1,因此老许从某度中找了一个支持http2的链接继续验证。

Bina cap jari JA3 anda sendiri dengan Go

看过Go发起HTTP2.0请求流程析(前篇)这篇文章的同学应该知道,http2连接在建立时需要发送PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n这么一个字符串。很明显,在自定义了DialTLSContext函数之后相关流程缺失。此时,我们该如何构建http2的专属指纹呢?

http2的专属指纹

通过DialTLSContext拨号之后只能得到一个已经完成TLS握手的连接,此时它还不支持http2的数据帧多路复用等特性。所以,我们需要自己构建一个支持http2各种特性的连接。

下面,我们通过golang.org/x/net/http2来完成自定义TLS握手流程后的http2请求。

// 手动拨号,得到一个已经完成TLS握手后的连接
con, err := tr.DialTLSContext(context.Background(), "tcp", "dss0.bdstatic.com:443")
if err != nil {
 fmt.Println("DialTLSContext", err)
 return
}

// 构建一个http2的连接
tr2 := http2.Transport{}
// 这一步很关键,不可缺失
h2Con, err := tr2.NewClientConn(con)
if err != nil {
 fmt.Println("NewClientConn", err)
 return
}

req, _ := http.NewRequest("GET", "https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/topnav/newzhidao-da1cf444b0.png", nil)
// 向一个支持http2的链接发起请求并读取请求状态
resp2, err := h2Con.RoundTrip(req)
if err != nil {
 fmt.Println("RoundTrip", err)
 return
}
io.CopyN(io.Discard, resp2.Body, 2<<10)
resp2.Body.Close()
fmt.Println("响应code: ", resp2.StatusCode)

结果如下。

Bina cap jari JA3 anda sendiri dengan Go

可以看到,最终在自定义JA3指纹后,http2的请求也能正常读取。至此,在支持http2的请求中构建专属的JA3指纹就完成了(生成JA3指纹的信息在clientHelloMsg中,完成本部分仅是为了确保从发起请求到读取响应都能够正常进行)。

Beberapa perkataan tambahan, melengkapkan permintaan http2 secara manual NewClientConnmempunyai had yang besar. Contohnya, anda perlu mengurus sendiri kitaran hayat sambungan, tidak boleh menyambung semula secara automatik, dsb. Sudah tentu, ini semua perkara untuk kemudiannya Jika terdapat keperluan sebenar untuk ini, pembangun mungkin perlu mencabut pakej bersih daripada kod sumber go dan mengekalkannya sendiri.

Atas ialah kandungan terperinci Bina cap jari JA3 anda sendiri dengan Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:Go语言进阶学习. Jika ada pelanggaran, sila hubungi admin@php.cn Padam