Maison >développement back-end >Golang >Créez votre propre empreinte digitale JA3 avec Go

Créez votre propre empreinte digitale JA3 avec Go

Go语言进阶学习
Go语言进阶学习avant
2023-07-24 16:20:53875parcourir
Dans cet article, nous passerons brièvement en revue le processus de prise de contact https et expliquerons ce que sont les empreintes digitales JA3 et comment personnaliser les empreintes digitales JA3 exclusives avec Go en fonction des questions soulevées par les lecteurs.
Créez votre propre empreinte digitale JA3 avec Go

Le plan de cet article est le suivant. Veuillez suivre les idées de Lao Xu et créer progressivement votre propre empreinte digitale JA3.

Créez votre propre empreinte digitale JA3 avec Go

Revoir le processus de prise de contact HTTPS

Avant de commencer officiellement à comprendre ce qu'est l'empreinte digitale JA3, nous examinons d'abord le processus de prise de contact HTTPS, qui vous aidera à comprendre ce qui suit.

J'ai codé plus de 2 000 lignes de code juste pour clarifier le processus de prise de contact TLS. Cet article analyse principalement le processus d'authentification unidirectionnelle HTTPS et d'authentification bidirectionnelle (TLS1.3).

Dans Authentification unidirectionnelle, le client n'a pas besoin de certificat, il lui suffit de vérifier que le certificat du serveur est légal. Le processus de prise de contact et les messages échangés sont les suivants.

Créez votre propre empreinte digitale JA3 avec Go

Dans authentification bidirectionnelle, le serveur et le client doivent vérifier la légitimité du certificat de l'autre partie. Le processus de prise de contact et les messages échangés sont les suivants.

Créez votre propre empreinte digitale JA3 avec Go

Comparaison de l'authentification unidirectionnelle et de l'authentification bidirectionnelle :

  1. Dans l'authentification unidirectionnelle et l'authentification bidirectionnelle, la totalité des données n'est envoyée et reçue que trois fois, et les données envoyées en une seule fois contiennent un ou plusieurs messages

  2. clientHelloMsg et serverHelloMsgNon chiffré, tous les messages envoyés par la suite sont chiffrésclientHelloMsgserverHelloMsg未经过加密,之后发送的消息均做了加密处理

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

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

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

    🎜🎜🎜🎜Le client et le serveur calculeront chacun la clé deux fois, et le timing de calcul est respectivement Lire le HelloMsg et finishedMsgAprès 🎜🎜🎜🎜🎜🎜par rapport à l'authentification unidirectionnelle, le serveur envoie plus de certificateRequestMsgTLS13 message 🎜🎜🎜🎜🎜🎜Par rapport à l'authentification unidirectionnelle, le client envoie plus de certificateMsgTLS13etcertificateVerifyMsgdeux messages 🎜

Qu'il s'agisse d'une authentification unidirectionnelle ou d'une authentification bidirectionnelle, la compréhension par le serveur des informations de base du client repose entièrement sur le fait que le client l'informe activement au serveur, et les informations les plus critiques ne sont 客户端支持的TLS版本客户端支持的加密套件(cipherSuites)客户端支持的签名算法和客户端支持的密钥交换协议以及其对应的公钥。这些信息均在包含clientHelloMsg中,而这些信息也是生成JA3指纹的关键信息,并且clientHelloMsgserverHelloMsgnon cryptées. Non crypté signifie que la difficulté de modification est réduite, ce qui nous offre également la possibilité de personnaliser notre propre empreinte digitale JA3.

"

Si vous souhaitez en savoir plus sur le processus de prise de contact HTTPS, veuillez lire l'article suivant :

Codez plus de 2 000 lignes de code juste pour que ce soit clair.

Codez plus de 2 000 lignes de code juste pour que ce soit clair. Processus de prise de contact TLS (suite)

Qu'est-ce que l'empreinte digitale JA3

J'ai déjà dit tant de choses, alors qu'est-ce que l'empreinte digitale JA3 exactement ? Selon l'article Open Sourcing JA3, Lao Xu l'a simplement compris comme JA3 est une méthode d'identification en ligne des empreintes digitales des clients TLS.

该方法用于收集clientHelloMsg数据包中以下字段的十进制字节值:Version TLSChiffres acceptésListe des extensionsCourbes elliptiques et Formats de courbe elliptique。然后,它将这些值串联起来,使用“,”来分隔各个字段,同时使用“ -”来分隔各个字段中的值。最后,计算这些字符串的md5哈希值,即得到易于使用和共享的长度为32老许将John Althouse文章中的抓包图结合Go源码中的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px; marge gauche : 2 px ; couleur d'arrière-plan : rgba (27, 31, 35, 0,05) ; famille de polices : « Operator Mono », Consolas, Monaco, Menlo, monospace ; coupure de mot : break-all ; couleur : rgb ( 255, 93, 108);">clientHelloMsg结构体做了字段一一映射。clientHelloMsg数据包中以下字段的十进制字节值:TLS VersionAccepted CiphersList of ExtensionsElliptic CurvesElliptic Curve Formats。然后,它将这些值串联起来,使用“,”来分隔各个字段,同时使用“-”来分隔各个字段中的值。最后,计算这些字符串的md5哈希值,即得到易于使用和共享的长度为32字符的指纹。

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

Créez votre propre empreinte digitale JA3 avec Go
细心的同学可能已经发现了,根据前文描述JA3指纹总共有5个数据字段,而上Il s'agit de l'extension TLS 4.准备了一个单元测试,有兴趣深入研的同学可以通过这个单元测试进行调试分析。

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指纹如下。

Créez votre propre empreinte digitale JA3 avec Go

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

Créez votre propre empreinte digitale JA3 avec Go

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

Créez votre propre empreinte digitale JA3 avec 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)

结果如下。

Créez votre propre empreinte digitale JA3 avec Go

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

Quelques mots supplémentaires, compléter manuellement les requêtes http2 NewClientConna de grandes limites. Par exemple, vous devez gérer vous-même le cycle de vie de la connexion, vous ne pouvez pas vous reconnecter automatiquement, etc. Bien sûr, tout cela sera pour plus tard. S'il y a un réel besoin, les développeurs devront peut-être extraire le package net du code source go et le maintenir eux-mêmes.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer