Heim  >  Artikel  >  Backend-Entwicklung  >  Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

Go语言进阶学习
Go语言进阶学习nach vorne
2023-07-24 16:20:53804Durchsuche
In diesem Artikel gehen wir kurz auf den https-Handshake-Prozess ein und erklären anhand von Leserfragen, was JA3-Fingerabdrücke sind und wie man exklusive JA3-Fingerabdrücke mit Go anpassen kann.
Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

Die Gliederung dieses Artikels lautet wie folgt. Bitte folgen Sie den Ideen von Lao Xu und erstellen Sie nach und nach Ihren eigenen JA3-Fingerabdruck.

Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

Überprüfung des HTTPS-Handshake-Prozesses

Bevor wir offiziell beginnen zu verstehen, was JA3-Fingerabdruck ist, überprüfen wir zunächst den HTTPS-Handshake-Prozess, der uns beim Verständnis des Folgenden helfen wird.

Ich habe mehr als 2.000 Codezeilen codiert, um den TLS-Handshake-Prozess zu verdeutlichen. In diesem Artikel wird hauptsächlich der HTTPS-Einweg-Authentifizierungsprozess und der Zwei-Wege-Authentifizierungsprozess (TLS1.3) analysiert.

Bei der Einseitigen Authentifizierung benötigt der Client kein Zertifikat, er muss lediglich überprüfen, ob das Serverzertifikat legal ist. Der Handshake-Prozess und die ausgetauschten Nachrichten sind wie folgt.

Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

Bei der Zwei-Wege-Authentifizierung müssen sowohl der Server als auch der Client die Legitimität des Zertifikats der anderen Partei überprüfen. Der Handshake-Prozess und die ausgetauschten Nachrichten sind wie folgt.

Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

Vergleich von Einweg-Authentifizierung und Zwei-Wege-Authentifizierung:

  1. Bei der Einweg-Authentifizierung und der Zwei-Wege-Authentifizierung werden die gesamten Daten nur dreimal gesendet und empfangen, und die einmal gesendeten Daten enthalten eine oder mehrere Nachrichten

  2. serverHelloMsgNicht verschlüsselt, alle danach gesendeten Nachrichten werden verschlüsseltclientHelloMsgserverHelloMsg未经过加密,之后发送的消息均做了加密处理

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

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

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

    🎜🎜🎜🎜Client und Server berechnen den Schlüssel jeweils zweimal und Der Berechnungszeitpunkt ist jeweils Lesen Sie den HelloMsg und finishedMsgNach 🎜🎜🎜🎜🎜🎜Im Vergleich zur Einwegauthentifizierung sendet der Server mehr certificateRequestMsgTLS13 Nachricht 🎜🎜🎜🎜🎜🎜Im Vergleich zur Einwegauthentifizierung sendet der Client mehr certificateVerifyMsgtwo message 🎜

Ob es sich um eine einseitige oder eine zweiseitige Authentifizierung handelt, das Verständnis des Servers für die grundlegenden Informationen des Clients hängt vollständig davon ab, dass der Client den Server aktiv darüber informiert, und die kritischeren Informationen sind „nicht verschlüsselt“. Unverschlüsselt bedeutet, dass die Schwierigkeit der Änderung verringert wird, was uns auch die Möglichkeit bietet, unseren eigenen JA3-Fingerabdruck anzupassen. 客户端支持的TLS版本客户端支持的加密套件(cipherSuites)客户端支持的签名算法和客户端支持的密钥交换协议以及其对应的公钥。这些信息均在包含clientHelloMsg中,而这些信息也是生成JA3指纹的关键信息,并且clientHelloMsgserverHelloMsg"

Wenn Sie mehr Details über den HTTPS-Handshake-Prozess erfahren möchten, lesen Sie bitte den folgenden Artikel: Codieren Sie mehr als 2.000 Codezeilen, nur um es klarer zu machen.

Codieren Sie mehr als 2.000 Codezeilen Nur um es klarzustellen. TLS-Handshake-Prozess (Fortsetzung)

Was ist ein JA3-Fingerabdruck? Ich habe schon so viel gesagt, was genau ist ein JA3-Fingerabdruck? Laut dem Artikel Open Sourcing JA3 hat Lao Xu es einfach so verstanden, dass JA3 eine Methode zur Online-Identifizierung von TLS-Client-Fingerabdrücken ist.

该方法用于收集TLS-VersionAkzeptierte ChiffrenListe der ErweiterungenElliptische Kurven und Elliptische Kurvenformate -“来分隔各个字段中的值.最后,计算这些字符串的md5哈希值,即得到易于使用和共享的长度为32字符的指纹.clientHelloMsg数据包中以下字段的十进制字节值:TLS VersionAccepted CiphersList of ExtensionsElliptic CurvesElliptic Curve Formats。然后,它将这些值串联起来,使用“,”来分隔各个字段,同时使用“-”来分隔各个字段中的值。最后,计算这些字符串的md5哈希值,即得到易于使用和共享的长度为32字符的指纹。

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

为了更近一步描述清楚这些数据的来源,老许将Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

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

https://github.com/Isites/go-coder/blob/master/http2/tls/handsh/msg_test.go
JA3指纹用途

根据前文的描述,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指纹如下。

Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

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

Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

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

Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

看过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)

结果如下。

Erstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck

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

Ein paar zusätzliche Worte: Das manuelle Ausfüllen von http2-Anfragen NewClientConnhat große Einschränkungen. Beispielsweise müssen Sie den Lebenszyklus der Verbindung selbst verwalten, können die Verbindung nicht automatisch wiederherstellen usw. Natürlich sind dies alles Dinge für später. Wenn dies tatsächlich erforderlich ist, müssen Entwickler möglicherweise das Netzpaket aus dem Go-Quellcode abzweigen und es selbst verwalten.

Das obige ist der detaillierte Inhalt vonErstellen Sie mit Go Ihren eigenen JA3-Fingerabdruck. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:Go语言进阶学习. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen