0%

突破限制访问-修改ja3指纹

写在前面

因为在t00ls上看到有人提问,代理了ip也无法突破限制访问


我就想到了可能是对方网站是识别了你的tls特征
那么就需要修改这些特征,去突破访问限制

入门ja3指纹

TLS会话

因为ja3指纹是基于TLS协议的,所以要先简单了解一下这个协议
TLS是ssl的进阶版本,用于加密会话
当初始化一个TLS会话的时候,需要进行先进行最基本的三次握手
在三次握手后,客户端会向服务端发送一个Client Hello包,然后服务端向客户端发送Server Hello包,这里我们主要关注这个Client Hello包

Client Hello包基本结构



这里只需要关注几个字段就行了

version:TLS的版本,这里是0x0303



Cipher Suites:列举出客户端支持的加密算法,每一种加密算法对应一个hex值



一系列Extension,每个都有不同的含义,这里不需要关注具体用处,只要知道是用一个十六进制值去代表每一种extension的就可以了

ja3指纹计算

ja3的计算主要就是由上面那几个字段的十进制组合在一起,然后计算他们的md5,格式如下:
TLSVersion,Cipher Suites,Extensions Type,Supported Groups,Elliptic curves point formats
当一个字段有不同的类型,就用 “-” 按照顺序依次去连接,这个顺序很重要一会儿会提到
例如我这里就是
771,4866-4867-4865-157-49313-49309-156-49312-49308-61-60-53-47-163-159-52394-49315-49311-49239-49235-162-158-49314-49310-49238-49234-107-106-196-195-103-64-190-189-57-56-136-135-51-50-69-68-49196-49200-49327-49325-49188-49192-49162-49172-49233-49232-192-186-132-65-52393-52392-49245-49249-49195-49199-49326-49324-49244-49248-49267-49271-49187-49191-49266-49270-49161-49171-255,0-11-10-16-22-23-49-13-43-45-51-21,29-23-30-25-24,0-1-2
进行md5加密后就是ja3指纹了
a6b4648af79cb0e6c9070f2fca7d5ac2

下面我依次介绍每块第一个数字的由来

771就是0x0303的十进制



4866就是,0x1302的十进制



0就是Extension:Server Name的type



29就是Extension Supported Groups中的Supported Groups第一个



0就是Extension ec_point_formats中Elliptic curves point formats第一个

在wireshark最下面也会有显示这个ja3,但是这个并不会真正的存在于数据包中,而是服务端提取到客户端的相应字段进行计算后得到的

伪造ja3指纹

用不同代理去访问网站

这个网站可以看到自己的ja3指纹 https://kawayiyi.com/tls
我这里是用pandavpn的全局模式
可以看到我的ip是107.187.83.12,我的tlsHashMd5也就是ja3指纹是6e43eefeaec91453751b092058ec8dd2
当我换一个ip去访问的时候

可以看到我的ip虽然变成了139.64.165.246,但是tlsHashMd5(ja3指纹)仍然是6e43eefeaec91453751b092058ec8dd2
所以有时候就算各种换代理也无法访问网站可能就是这个原因,被记录下了ja3指纹

修改ja3指纹

那么当我们去修改Client Hello里面的一些信息,就可以达到修改ja3指纹突破访问限制,下面我直接贴出修改代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
import random
import requests,time

ORIGIN_CIPHERS = ('ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES')


class DESAdapter(HTTPAdapter):
def __init__(self, *args, **kwargs):
CIPHERS = ORIGIN_CIPHERS.split(':')
random.shuffle(CIPHERS)
CIPHERS = ':'.join(CIPHERS)
self.CIPHERS = CIPHERS + ':!aNULL:!eNULL:!MD5'
return super().__init__(*args, **kwargs)


def init_poolmanager(self, *args, **kwargs):
context = create_urllib3_context(ssl_version=2,ciphers=self.CIPHERS)
kwargs['ssl_context'] = context
return super(DESAdapter, self).init_poolmanager(*args, **kwargs)

# def proxy_manager_for(self, *args, **kwargs):
# context = create_urllib3_context(ssl_version=2,ciphers=self.CIPHERS)
# kwargs['ssl_context'] = context
# super(DESAdapter, self).proxy_manager_for(*args, **kwargs)

def SpoofJa3Get(url,headers):
s = requests.Session()
s.headers.update(headers)
s.mount(url, DESAdapter())
resp = s.get(url)
return resp

for _ in range(5):
resp = SpoofJa3Get('https://kawayiyi.com/tls',{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67'})
data = resp.json()
print(data['tlsHashMd5'])

这个是运行效果,可以看到ja3指纹确实都改变了

接下来简单讲解一下代码
这里主要是去继承原先的HTTPAdapter,在构造函数中将Cipher Suites进行打乱随机排序,然后去重写init_poolmanager
可以看到官方文档介绍这个函数

Initializes a urllib3 PoolManager.
   This method should not be called
   from user code, and is only exposed for use when subclassing the
   :class:`HTTPAdapter `.
   :param connections: The number of urllib3 connection pools to cache.
   :param maxsize: The maximum number of connections to save in the pool.
   :param block: Block when no free connections are available.

只有短短的一句,根据名称猜测就是初始化一个连接池之类的,然后每次访问别的网站都要基于这个连接池去访问,类似与urllib3的PoolManager

create_urllib3_context 官方文档介绍我就不贴出来了,具体可以看
https://github.com/urllib3/urllib3/blob/main/src/urllib3/util/ssl_.py#L221
简单说一下就是创建并且配置一个ssl内容的实例,并且返回这个实例,但是给出的参数与ja3指纹相关的只有

  • ssl version
  • cipher suites

ssl版本我们不能随便修改,不然就会出错,能修改的只有支持的加密算法
后面的代码我就不做过多解释了,应该都是很简单的

后记

至于怎么去修改Extensions Type,Supported Groups,Elliptic curves point formats来进行修改ja3指纹,我就不太清楚了
之前在stackoverflow上面问了一个跟我有同样疑惑的网友,问他现在解决没有,但是评论不知道为什么被系统秒删了,我也就没去进行深究了
https://stackoverflow.com/questions/69982651/tls-adapter-for-extentions-with-python3-requests/74032540#74032540

参考链接