sardanioss/httpcloak

GitHub: sardanioss/httpcloak

一款 Go 实现的浏览器指纹模仿 HTTP 客户端,通过模拟 Chrome/Firefox/Safari 的 TLS 与 HTTP 特征来绕过机器人检测。

Stars: 940 | Forks: 68

httpcloak

Go Reference PyPI npm NuGet

Every Byte of your Request Indistinguishable from Chrome.


## 问题 机器人检测不再只检查你的 User-Agent。 它会指纹识别你的 **TLS 握手**。你的 **HTTP/2 帧**。你的 **QUIC 参数**。请求头的顺序。你的 SNI 是否加密。 一点不匹配 = 被拦截。 ## 解决方案 ``` import httpcloak r = httpcloak.get("https://target.com", preset="chrome-latest") ``` 仅此而已。完整的浏览器传输层指纹。 ## 模拟的内容
### 🔐 TLS 层 - JA3 / JA4 指纹 - GREASE 随机化 - 后量子 X25519MLKEM768 - ECH(加密客户端问候) ### 🚀 传输层 - HTTP/2 SETTINGS 帧 - WINDOW_UPDATE 值 - 流优先级(HPACK) - QUIC 传输参数 - HTTP/3 GREASE 帧 - TCP/IP 栈(TTL、MSS、窗口大小) ### 🧠 头部层 - Sec-Fetch-* 一致性 - 客户端提示(Sec-Ch-UA) - Accept / Accept-Language - 请求头顺序 - Cookie 持久化
## 结果 ``` ┌─────────────────────────────────┐ │ ECH (Encrypted Client Hello) │ ├─────────────────────────────────┤ │ WITHOUT: sni=plaintext │ │ WITH: sni=encrypted + │ └─────────────────────────────────┘ ``` ``` ┌─────────────────────────────────┐ │ HTTP/3 Fingerprint Match │ ├─────────────────────────────────┤ │ Protocol: h3 + │ │ QUIC Version: 1 + │ │ Transport Params: + │ │ GREASE Frames: + │ └─────────────────────────────────┘ ``` ## 与 curl_cffi 对比 ``` ┌────────────────────────────────┬────────────────────────────────┐ │ BOTH LIBRARIES │ HTTPCLOAK ONLY │ ├────────────────────────────────┼────────────────────────────────┤ │ │ │ │ + TLS fingerprint (JA3/JA4) │ + HTTP/3 fingerprinting │ │ + HTTP/2 fingerprint │ + ECH (encrypted SNI) │ │ + Post-quantum TLS │ + MASQUE proxy │ │ + Bot score: 99 │ + Domain fronting │ │ │ + Certificate pinning │ │ │ + Go, Python, Node.js, C# │ │ │ │ └────────────────────────────────┴────────────────────────────────┘ ``` ## 安装 ``` pip install httpcloak # Python npm install httpcloak # Node.js go get github.com/sardanioss/httpcloak # Go dotnet add package HttpCloak # C# ``` ## 快速开始 ### Python ``` import httpcloak # 简单请求 r = httpcloak.get("https://example.com", preset="chrome-latest") print(r.status_code, r.protocol) # 使用 JSON 的 POST 请求 r = httpcloak.post("https://httpbin.org/post", json={"key": "value"}, preset="chrome-latest" ) # 自定义标头 r = httpcloak.get("https://httpbin.org/headers", headers={"X-Custom": "value"}, preset="chrome-latest" ) ``` ### Go ``` import ( "context" "github.com/sardanioss/httpcloak/client" ) // Simple request c := client.NewClient("chrome-latest") defer c.Close() resp, _ := c.Get(ctx, "https://example.com", nil) body, _ := resp.Text() fmt.Println(resp.StatusCode, resp.Protocol) // POST with JSON jsonBody := []byte(`{"key": "value"}`) resp, _ = c.Post(ctx, "https://httpbin.org/post", bytes.NewReader(jsonBody), map[string][]string{"Content-Type": {"application/json"}}, ) // Custom headers resp, _ = c.Get(ctx, "https://httpbin.org/headers", map[string][]string{ "X-Custom": {"value"}, }) ``` ### Node.js ``` import httpcloak from "httpcloak"; // Simple request const session = new httpcloak.Session({ preset: "chrome-latest" }); const r = await session.get("https://example.com"); console.log(r.statusCode, r.protocol); // POST with JSON const r = await session.post("https://httpbin.org/post", { json: { key: "value" } }); // Custom headers const r = await session.get("https://httpbin.org/headers", { headers: { "X-Custom": "value" } }); session.close(); ``` ### C# ``` using HttpCloak; // Simple request using var session = new Session(preset: Presets.Chrome145); var r = session.Get("https://example.com"); Console.WriteLine($"{r.StatusCode} {r.Protocol}"); // POST with JSON var r = session.PostJson("https://httpbin.org/post", new { key = "value" } ); // Custom headers var r = session.Get("https://httpbin.org/headers", headers: new Dictionary { ["X-Custom"] = "value" } ); ``` ## 功能特性 ### 🔐 ECH(加密客户端问候) 隐藏你正在连接哪个域名,防止网络观察者窥探。 ``` session = httpcloak.Session( preset="chrome-latest", ech_from="cloudflare.com" # Fetches ECH config from DNS ) ``` Cloudflare 追踪显示 `sni=encrypted` 而非 `sni=plaintext`。 ### ⚡ 会话恢复(0-RTT) TLS 会话票据让你看起来像回头客。 ``` # 在任意 Cloudflare 站点上预热 session.get("https://cloudflare.com/") session.save("session.json") # 应用于目标网站 session = httpcloak.Session.load("session.json") r = session.get("https://target.com/") # Bot score: 99 ``` 跨域预热有效,因为 Cloudflare 站点共享 TLS 基础设施。 ### 🌐 通过代理的 HTTP/3 QUIC 通过代理的两种方法: | 方法 | 工作原理 | |--------|--------------| | **SOCKS5 UDP ASSOCIATE** | 代理转发 UDP 数据包。大多数住宅代理支持此功能。 | | **MASQUE(CONNECT-UDP)** | RFC 9298。通过 HTTP/3 隧道转发 UDP。仅限高级提供商使用。 | ``` # 带 UDP 的 SOCKS5 session = httpcloak.Session(proxy="socks5://user:pass@proxy:1080") # MASQUE session = httpcloak.Session(proxy="masque://proxy:443") ``` 已知 MASQUE 提供商(自动识别):Bright Data、Oxylabs、Smartproxy、SOAX。 **推测性 TLS**(可选):CONNECT 与 TLS ClientHello 一起发送,节省一个代理往返(约快 25%)。为兼容的代理启用: ``` session = httpcloak.Session(proxy="socks5://...", enable_speculative_tls=True) ``` ### 🎭 域名前置 连接到与 TLS SNI 中显示的不同主机。 ``` client := httpcloak.NewClient("chrome-latest", httpcloak.WithConnectTo("public-cdn.com", "actual-backend.internal"), ) ``` ### 📌 证书固定 ``` client.PinCertificate("sha256/AAAA...", httpcloak.PinOptions{IncludeSubdomains: true}) ``` ### 🪝 请求钩子 ``` client.OnPreRequest(func(req *http.Request) error { req.Header.Set("X-Custom", "value") return nil }) client.OnPostResponse(func(resp *httpcloak.Response) { log.Printf("Got %d from %s", resp.StatusCode, resp.FinalURL) }) ``` ### ⏱️ 请求计时 ``` fmt.Printf("DNS: %dms, TCP: %dms, TLS: %dms, Total: %dms\n", resp.Timing.DNSLookup, resp.Timing.TCPConnect, resp.Timing.TLSHandshake, resp.Timing.Total) ``` ### 🔄 协议选择 ``` session = httpcloak.Session(preset="chrome-latest", http_version="h3") # Force HTTP/3 session = httpcloak.Session(preset="chrome-latest", http_version="h2") # Force HTTP/2 session = httpcloak.Session(preset="chrome-latest", http_version="h1") # Force HTTP/1.1 ``` 自动模式优先尝试 HTTP/3,失败后优雅降级。 ### 🖥️ TCP/IP 指纹识别 反机器人系统会检查 TCP SYN 包参数(TTL、窗口大小、MSS、窗口缩放)来验证你声称的操作系统是否匹配。如果一个声称使用 Chrome 的 Windows 请求却带有 Linux TCP 参数(TTL=64),会立即被标记。 httpcloak 会为每个预设平台自动设置正确的 TCP/IP 指纹。你也可以手动覆盖: ``` session = httpcloak.Session( preset="chrome-latest-windows", tcp_ttl=128, # Windows=128, Linux/macOS=64 tcp_window_size=64240, # Windows=64240, Linux/macOS=65535 tcp_window_scale=8, # Windows=8, Linux=7, macOS=6 tcp_mss=1460, # Standard Ethernet MTU ) ``` **Go:** ``` client := client.NewClient("chrome-latest-windows", client.WithTCPFingerprint(fingerprint.TCPFingerprint{ TTL: 128, MSS: 1460, WindowSize: 64240, WindowScale: 8, DFBit: true, }), ) ``` **Node.js:** ``` const session = new httpcloak.Session({ preset: "chrome-latest-windows", tcpTtl: 128, tcpWindowSize: 64240, tcpWindowScale: 8, }); ``` **C#:** ``` var session = new Session( preset: Presets.Chrome145Windows, tcpTtl: 128, tcpWindowSize: 64240, tcpWindowScale: 8 ); ``` 内置平台配置:Windows(TTL=128,WS=8)、Linux(TTL=64,WS=7)、macOS(TTL=64,WS=6)。 ### 🔀 运行时代理切换 在不创建新连接的情况下切换代理。适合代理轮换。 ``` session = httpcloak.Session(preset="chrome-latest") # 从直接连接开始 r = session.get("https://api.ipify.org") print(f"Direct IP: {r.text}") # 切换到代理 1 session.set_proxy("http://proxy1.example.com:8080") r = session.get("https://api.ipify.org") print(f"Proxy 1 IP: {r.text}") # 切换到代理 2 session.set_proxy("socks5://proxy2.example.com:1080") r = session.get("https://api.ipify.org") print(f"Proxy 2 IP: {r.text}") # 回到直接连接 session.set_proxy("") ``` **拆分代理配置** - 对 HTTP/2 和 HTTP/3 使用不同的代理: ``` session = httpcloak.Session(preset="chrome-latest") # HTTP/1.1 和 HTTP/2 的 TCP 代理 session.set_tcp_proxy("http://tcp-proxy.example.com:8080") # HTTP/3 的 UDP 代理(需要 SOCKS5 UDP 关联或 MASQUE) session.set_udp_proxy("socks5://udp-proxy.example.com:1080") # 检查当前配置 print(session.get_tcp_proxy()) # TCP proxy URL print(session.get_udp_proxy()) # UDP proxy URL ``` ### 📋 请求头顺序自定义 控制请求头的发送顺序,适用于高级指纹识别场景。 ``` session = httpcloak.Session(preset="chrome-latest") # 获取当前标头顺序(来自预设) print(session.get_header_order()) # 设置自定义标头顺序 session.set_header_order([ "accept-language", "sec-ch-ua", "accept", "sec-fetch-site", "sec-fetch-mode", "user-agent", "sec-ch-ua-platform", "sec-ch-ua-mobile" ]) # 使用自定义顺序发起请求 r = session.get("https://example.com") # 重置为预设的默认顺序 session.set_header_order([]) ``` **JavaScript:** ``` session.setHeaderOrder(["accept-language", "sec-ch-ua", "accept", ...]); console.log(session.getHeaderOrder()); session.setHeaderOrder([]); // Reset to default ``` **C#:** ``` session.SetHeaderOrder(new[] { "accept-language", "sec-ch-ua", "accept", ... }); Console.WriteLine(string.Join(", ", session.GetHeaderOrder())); session.SetHeaderOrder(null); // Reset to default ``` **Go:** ``` c.SetHeaderOrder([]string{"accept-language", "sec-ch-ua", "accept", ...}) fmt.Println(c.GetHeaderOrder()) c.SetHeaderOrder(nil) // Reset to default ``` ### 📤 流式传输与上传 ``` # 流式大文件下载 stream = session.get_stream("https://example.com/large-file.zip") print(f"Size: {stream.content_length} bytes") with open("file.zip", "wb") as f: while True: chunk = stream.read(8192) if not chunk: break f.write(chunk) stream.close() # 迭代器模式 for chunk in session.get_stream(url).iter_content(chunk_size=8192): process(chunk) # 多部分上传 r = session.post(url, files={ "file": ("filename.jpg", file_bytes, "image/jpeg") }) ``` ### 🔒 身份验证 ``` # 基本身份验证 r = httpcloak.get("https://api.example.com/data", auth=("username", "password"), preset="chrome-latest" ) # 会话级身份验证 session = httpcloak.Session( preset="chrome-latest", auth=("username", "password") ) ``` ### ⏱️ 超时与重试 ``` # 超时 session = httpcloak.Session(preset="chrome-latest", timeout=30) # 每个请求的超时 r = session.get("https://slow-api.com/data", timeout=60) ``` ``` // Go: Timeout and retry configuration client := client.NewClient("chrome-latest", client.WithTimeout(30 * time.Second), client.WithRetry(3), // Retry 3 times on 429, 500, 502, 503, 504 client.WithRetryConfig( 5, // Max retries 500 * time.Millisecond, // Min backoff 10 * time.Second, // Max backoff []int{429, 503}, // Status codes to retry ), ) ``` ### 🚫 重定向控制 ``` // Disable automatic redirects client := client.NewClient("chrome-latest", client.WithoutRedirects(), ) resp, _ := client.Get(ctx, "https://example.com/redirect", nil) fmt.Println(resp.StatusCode) // 302 fmt.Println(resp.GetHeader("location")) // Redirect URL ``` ### 🔃 刷新(浏览器页面刷新) 模拟浏览器页面刷新 - 关闭所有 TCP/QUIC 连接但保持 TLS 会话缓存。下次请求时连接使用 TLS 恢复(就像真实浏览器一样)。 ``` session = httpcloak.Session(preset="chrome-latest") # 发起一些请求 session.get("https://example.com/page1") session.get("https://example.com/page2") # 模拟浏览器刷新(F5) session.refresh() # 下一个请求使用 TLS 恢复,看起来像回访用户 session.get("https://example.com/page1") ``` **Go:** ``` session := httpcloak.NewSession("chrome-latest") session.Get(ctx, "https://example.com") session.Refresh() // Close connections, keep TLS cache session.Get(ctx, "https://example.com") // TLS resumption ``` **Node.js:** ``` session.refresh(); ``` **C#:** ``` session.Refresh(); ``` ### 🌐 预热(浏览器页面加载) 模拟真实浏览器页面加载 - 获取 HTML 页面及其所有子资源(CSS、JS、图片、字体),使用真实的请求头、优先级和时机。预热完成后,会话将包含 TLS 会话票据、Cookie 和缓存头。 ``` session = httpcloak.Session(preset="chrome-latest") # 获取页面 + 子资源,行为如同真实浏览器 session.warmup("https://example.com") # 后续请求看起来像是来自真实用户的跟进导航 r = session.get("https://example.com/api/data") ``` **Go:** ``` session := httpcloak.NewSession("chrome-latest") session.Warmup(ctx, "https://example.com") session.Get(ctx, "https://example.com/api/data") // Looks like real user ``` **Node.js:** ``` session.warmup("https://example.com"); ``` **C#:** ``` session.Warmup("https://example.com"); ``` ### 🔀 分叉(并行浏览器标签页) 创建 N 个会话,与父会话共享 Cookie 和 TLS 会话缓存,但拥有独立的连接。这模拟了多个浏览器标签页 - 相同的 Cookie、相同的 TLS 恢复票据、相同的指纹,但 TCP/QUIC 连接独立,支持并行请求。 ``` session = httpcloak.Session(preset="chrome-latest") session.warmup("https://example.com") # 创建 10 个并行“标签页”,共享 Cookie + TLS 缓存 tabs = session.fork(10) for i, tab in enumerate(tabs): threading.Thread( target=lambda t, n: t.get(f"https://example.com/page/{n}"), args=(tab, i) ).start() ``` **Go:** ``` session := httpcloak.NewSession("chrome-latest") session.Warmup(ctx, "https://example.com") tabs := session.Fork(10) for i, tab := range tabs { go func(t *httpcloak.Session, n int) { t.Get(ctx, fmt.Sprintf("https://example.com/page/%d", n)) }(tab, i) } ``` **Node.js:** ``` session.warmup("https://example.com"); const tabs = session.fork(10); await Promise.all(tabs.map((tab, i) => tab.get(`https://example.com/page/${i}`))); ``` **C#:** ``` session.Warmup("https://example.com"); var tabs = session.Fork(10); await Task.WhenAll(tabs.Select((tab, i) => Task.Run(() => tab.Get($"https://example.com/page/{i}")) )); ``` ### 🌍 本地地址绑定 将传出连接绑定到特定的本地 IP 地址。在 IPv6 轮换场景中非常有用,当你的机器拥有多个分配的 IP 时。 ``` # 绑定到特定 IPv6 地址 session = httpcloak.Session( preset="chrome-latest", local_address="2001:db8::1" ) # 所有请求使用此源 IP r = session.get("https://api.ipify.org") print(r.text) # Shows 2001:db8::1 # IPv4 也适用 session = httpcloak.Session( preset="chrome-latest", local_address="192.168.1.100" ) ``` **Go:** ``` session := httpcloak.NewSession("chrome-latest", httpcloak.WithLocalAddress("2001:db8::1"), ) ``` **Node.js:** ``` const session = new httpcloak.Session({ preset: "chrome-latest", localAddress: "2001:db8::1" }); ``` **C#:** ``` var session = new Session( preset: Presets.Chrome145, localAddress: "2001:db8::1" ); ``` **注意:** 设置本地地址后,目标 IP 会自动筛选以匹配地址族(IPv6 本地 → 仅 IPv6 目标)。 ### 🔑 TLS 密钥日志记录 将 TLS 会话密钥写入文件,以便在 Wireshark 中解密流量。支持 HTTP/1.1、HTTP/2 和 HTTP/3。 ``` session = httpcloak.Session( preset="chrome-latest", key_log_file="/tmp/keys.log" ) # 发起请求 - 密钥写入文件 session.get("https://example.com") # 在 Wireshark 中:编辑 → 首选项 → 协议 → TLS → (预)主密钥日志文件名 ``` **Go:** ``` session := httpcloak.NewSession("chrome-latest", httpcloak.WithKeyLogFile("/tmp/keys.log"), ) ``` **Node.js:** ``` const session = new httpcloak.Session({ preset: "chrome-latest", keyLogFile: "/tmp/keys.log" }); ``` **C#:** ``` var session = new Session( preset: Presets.Chrome145, keyLogFile: "/tmp/keys.log" ); ``` 也支持 `SSLKEYLOGFILE` 环境变量(标准 NSS 密钥日志格式)。 ## API 参考 ### Python ``` import httpcloak # 模块级函数 httpcloak.get(url, **kwargs) httpcloak.post(url, **kwargs) httpcloak.put(url, **kwargs) httpcloak.patch(url, **kwargs) httpcloak.delete(url, **kwargs) httpcloak.head(url, **kwargs) httpcloak.options(url, **kwargs) # 会话类 session = httpcloak.Session( preset="chrome-latest", # Browser preset (default) proxy="socks5://...", # Proxy URL timeout=30, # Timeout in seconds http_version="h3", # Force protocol: h1, h2, h3, auto ech_from="cloudflare.com", # ECH config source auth=("user", "pass"), # Basic auth ) # 会话方法 session.get(url, **kwargs) session.post(url, data=None, json=None, **kwargs) session.get_stream(url) # Streaming download session.close() # 代理切换 session.set_proxy(url) # Set both TCP and UDP proxy session.set_tcp_proxy(url) # Set TCP proxy only (H1/H2) session.set_udp_proxy(url) # Set UDP proxy only (H3) session.get_proxy() # Get current proxy session.get_tcp_proxy() # Get current TCP proxy session.get_udp_proxy() # Get current UDP proxy # 标头顺序自定义 session.set_header_order(order) # Set custom header order (list of lowercase names) session.get_header_order() # Get current header order # 会话持久性(0-RTT 恢复) session.save("session.json") # Save to file session = Session.load("session.json") # Load from file data = session.marshal() # Export as string session = Session.unmarshal(data) # Import from string # 响应对象 response.status_code # HTTP status response.ok # True if status < 400 response.text # Body as string response.content # Body as bytes response.json() # Parse JSON response.headers # Response headers response.protocol # h1, h2, or h3 response.url # Final URL response.raise_for_status() # Raise on 4xx/5xx ``` ### Go ``` import "github.com/sardanioss/httpcloak/client" // Client creation c := client.NewClient("chrome-latest", client.WithTimeout(30 * time.Second), client.WithProxy("socks5://..."), client.WithRetry(3), client.WithoutRedirects(), client.WithInsecureSkipVerify(), ) defer c.Close() // Request methods resp, err := c.Get(ctx, url, headers) resp, err := c.Post(ctx, url, body, headers) resp, err := c.Put(ctx, url, body, headers) resp, err := c.Delete(ctx, url, headers) // Advanced request resp, err := c.Do(ctx, &client.Request{ Method: "GET", URL: url, Headers: map[string][]string{}, Body: io.Reader, Params: map[string]string{}, ForceProtocol: client.ProtocolHTTP3, FetchMode: client.FetchModeCORS, Referer: "https://example.com", }) // Proxy switching c.SetProxy(url) // Set both TCP and UDP proxy c.SetTCPProxy(url) // Set TCP proxy only (H1/H2) c.SetUDPProxy(url) // Set UDP proxy only (H3) c.GetProxy() // Get current proxy c.GetTCPProxy() // Get current TCP proxy c.GetUDPProxy() // Get current UDP proxy // Session persistence (0-RTT resumption) c.Save("session.json") // Save to file c, _ = client.Load("session.json") // Load from file data, _ := c.Marshal() // Export as string c, _ = client.Unmarshal(data) // Import from string // Response object resp.StatusCode resp.Protocol resp.Headers resp.Body // io.ReadCloser resp.Text() // (string, error) resp.Bytes() // ([]byte, error) resp.JSON(&v) // error resp.GetHeader(key) // string resp.IsSuccess() // bool resp.IsRedirect() // bool ``` ### Node.js ``` import httpcloak from "httpcloak"; // Session creation const session = new httpcloak.Session({ preset: "chrome-latest", proxy: "socks5://...", timeout: 30000, httpVersion: "h3", }); // Async methods await session.get(url, options) await session.post(url, { json, data, headers }) await session.put(url, options) await session.delete(url, options) // Sync methods session.getSync(url, options) session.postSync(url, options) session.close() // Proxy switching session.setProxy(url) // Set both TCP and UDP proxy session.setTcpProxy(url) // Set TCP proxy only (H1/H2) session.setUdpProxy(url) // Set UDP proxy only (H3) session.getProxy() // Get current proxy session.getTcpProxy() // Get current TCP proxy session.getUdpProxy() // Get current UDP proxy session.proxy // Property accessor (get/set) // Session persistence (0-RTT resumption) session.save("session.json") // Save to file session = httpcloak.Session.load("session.json") // Load from file const data = session.marshal() // Export as string session = httpcloak.Session.unmarshal(data) // Import from string // Response object response.statusCode response.ok response.text response.json() response.headers response.protocol ``` ### C# ``` using HttpCloak; // Session creation var session = new Session( preset: Presets.Chrome145, proxy: "socks5://...", timeout: 30 ); // Request methods session.Get(url, headers) session.Post(url, body, headers) session.PostJson(url, data, headers) session.Put(url, body, headers) session.Delete(url) session.Dispose() // Proxy switching session.SetProxy(url) // Set both TCP and UDP proxy session.SetTcpProxy(url) // Set TCP proxy only (H1/H2) session.SetUdpProxy(url) // Set UDP proxy only (H3) session.GetProxy() // Get current proxy session.GetTcpProxy() // Get current TCP proxy session.GetUdpProxy() // Get current UDP proxy session.Proxy // Property accessor (get/set) // Session persistence (0-RTT resumption) session.Save("session.json") // Save to file var session = Session.Load("session.json") // Load from file var data = session.Marshal() // Export as string var session = Session.Unmarshal(data) // Import from string // Response object response.StatusCode response.Ok response.Text response.Json() response.Headers response.Protocol ``` ## 浏览器预设 | 预设 | 平台 | PQ | H3 | |--------|----------|:--:|:--:| | `chrome-146` | 自动 | ✅ | ✅ | | `chrome-146-windows` | Windows | ✅ | ✅ | | `chrome-146-macos` | macOS | ✅ | ✅ | | `chrome-146-linux` | Linux | ✅ | ✅ | | `chrome-146-ios` | iOS | ✅ | ✅ | | `chrome-146-android` | Android | ✅ | ✅ | | `chrome-145` | 自动 | ✅ | ✅ | | `chrome-145-windows` | Windows | ✅ | ✅ | | `chrome-145-macos` | macOS | ✅ | ✅ | | `chrome-145-linux` | Linux | ✅ | ✅ | | `chrome-145-ios` | iOS | ✅ | ✅ | | `chrome-145-android` | Android | ✅ | ✅ | | `chrome-144` | 自动 | ✅ | ✅ | | `chrome-144-windows` | Windows | ✅ | ✅ | | `chrome-144-macos` | macOS | ✅ | ✅ | | `chrome-144-linux` | Linux | ✅ | ✅ | | `chrome-143` | 自动 | ✅ | ✅ | | `chrome-143-windows` | Windows | ✅ | ✅ | | `chrome-143-macos` | macOS | ✅ | ✅ | | `chrome-143-linux` | Linux | ✅ | ✅ | | `chrome-141` | 自动 | ✅ | ❌ | | `chrome-133` | 自动 | ✅ | ❌ | | `firefox-133` | 自动 | ❌ | ❌ | | `safari-18` | macOS | ❌ | ✅ | | `safari-18-ios` | iOS | ❌ | ✅ | | `safari-17-ios` | iOS | ❌ | ❌ | | `chrome-146-ios` | iOS | ✅ | ✅ | | `chrome-145-ios` | iOS | ✅ | ✅ | | `chrome-144-ios` | iOS | ✅ | ✅ | | `chrome-143-ios` | iOS | ✅ | ✅ | | `chrome-146-android` | Android | ✅ | ✅ | | `chrome-145-android` | Android | ✅ | ✅ | | `chrome-144-android` | Android | ✅ | ✅ | | `chrome-143-android` | Android | ✅ | ✅ | **PQ** = 后量子(X25519MLKEM768) · **H3** = HTTP/3 ## 测试工具 | 工具 | 测试内容 | |------|-------| | [tls.peet.ws](https://tls.peet.ws/api/all) | JA3、JA4、HTTP/2 Akamai | | [quic.browserleaks.com](https://quic.browserleaks.com/) | HTTP/3 QUIC 指纹 | | [cf.erisa.uk](https://cf.erisa.uk/) | Cloudflare 机器人评分 | | [cloudflare.com/cdn-cgi/trace](https://www.cloudflare.com/cdn-cgi/trace) | ECH 状态、TLS 版本 | ## 依赖项 浏览器指纹识别的定制分支: - [sardanioss/utls](https://github.com/sardanioss/utls) — TLS 指纹识别 - [sardanioss/quic-go](https://github.com/sardanioss/quic-go) — HTTP/3 指纹识别 - [sardanioss/net](https://github.com/sardanioss/net) — HTTP/2 帧指纹识别 ## 联系 - Discord:**sardanioss** - 邮箱:**sakshamsolanki126@gmail.com**

MIT License

标签:Accept 语言, Akamai 指纹, Bot 绕过, Chrome 模拟, Cookie 持久化, ECH, EVTX分析, Firefox 模拟, Go HTTP 客户端, Go 包, GREASE 随机化, HPACK, HTTP/1.1, HTTP/2, HTTP/2 指纹, HTTP/3, HTTP/3 指纹, HTTP 代理, JA3, JA4, MITM代理, MSS, npm, NuGet, pkg.go.dev, PyPI, QUIC 传输参数, Safari 模拟, Sec-Fetch 标头, SNI 加密, Stream 优先级, TCP/IP 栈, TLS 指纹, TTL, X25519MLKEM768, 代理支持, 会话复用, 会话管理, 加密层模拟, 告警, 多架构支持, 客户端提示, 日志审计, 标头顺序, 浏览器指纹模拟, 窗口大小, 逆向工具, 防检测