目录标题
-
- [tls-client-sharp 介绍:](#tls-client-sharp 介绍:)
- [bogdanfinn/tls-client 项目地址](#bogdanfinn/tls-client 项目地址)
- 使用tls-client-sharp参考代码:
- 参考代码:
- [tls-client.dll 下载地址:](#tls-client.dll 下载地址:)
- [tls-client.dll 、tls-client.so 网盘下载地址,版本 v1.15.1:](#tls-client.dll 、tls-client.so 网盘下载地址,版本 v1.15.1:)
我的使项目版本:
- 项目使用nuget包:tls-client-sharp 1.0.0
- 项目框架集:.NET 10
tls-client-sharp 介绍:
一个用于 bogdanfinn/tls-client 的 C# 封装,提供自定义的 HttpClientHandler。该封装可让你发起模拟主流浏览器 TLS 指纹的 HTTP 请求,从而帮助绕过反机器人保护机制。安装时,该封装会在首次运行时自动检查并从 GitHub 发布页下载所需的 tls-client 库,并将库文件存储在用户的临时文件夹中,以确保程序的可移植性。你无需手动下载 DLL 文件。
bogdanfinn/tls-client 项目地址
https://github.com/bogdanfinn/tls-client
使用tls-client-sharp参考代码:
csharp
using TlsClientWrapperSharp.Handlers;
using TlsClientWrapperSharp.Helpers;
using TlsClientWrapperSharp.Models;
// 1. Ensure the library is downloaded (checks for updates or missing file)
await TlsLibraryLoader.EnsureLibraryExistsAsync();
// 2. Initialize the handler with a specific browser identifier
var tlsClientHandler = new TlsClientHandler
{
TlsClientIdentifier = ClientIdentifier.Chrome133
};
// 3. Create a standard HttpClient using the handler
var httpClient = new HttpClient(tlsClientHandler);
// (Optional) Add headers as needed
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Language", "en-GB,en;q=0.9");
// 4. Make requests
var response = await httpClient.GetStringAsync("https://tls.browserleaks.com/tls");
Console.WriteLine(response);
参考代码:
设置了Http代理,tls-client可以设置指定浏览器版本的指纹,可以用于绕过TLS JA3 指纹风控拦截
csharp
using ConsoleOuBo.Model;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json.Nodes;
using TlsClientWrapperSharp.Handlers;
using TlsClientWrapperSharp.Helpers;
using TlsClientWrapperSharp.Models;
using static System.Net.WebRequestMethods;
namespace WsInspectorDemo
{
/// <summary>
/// 封装 agg111 登录接口调用和 Cookie 管理。
/// </summary>
public sealed class Agg111LoginClient : IDisposable
{
private readonly HttpClient _http;
/// <summary>
/// 是否使用代理
/// </summary>
private bool _usingProxy;
public CookieContainer Cookies { get; } = new();
/// <summary>
/// 初始化 Agg111LoginClient 实例。
/// </summary>
/// <param name="apiBase">apiBase 参数。</param>
/// <param name="timeoutSeconds">timeoutSeconds 参数。</param>
public Agg111LoginClient(string apiBase, int timeoutSeconds)
{
var proxySettings = CommonConfigHelpter.MyProxySettings;
_usingProxy = proxySettings is not null
&& !string.IsNullOrWhiteSpace(proxySettings.ServerAddress);
#if DEBUG
//调试,false 不用代理
//_usingProxy = false;
#endif
if (!_usingProxy)
{
//不用代理
_http = new HttpClient(new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.All,
UseCookies = true,
CookieContainer = Cookies,
UseProxy = false
})
{
Timeout = TimeSpan.FromSeconds(timeoutSeconds)
};
}
else
{
// HTTP代理
// Oxylabs 这里是 HTTP 代理。不要把同一个端点当成 SOCKS5 使用,
// 也不要在客户端里写死 host/port,否则 Apifox 与程序实际走的代理可能不同。
var proxyUri = new Uri($"http://{proxySettings.ServerAddress!.Trim()}:{proxySettings.Port}");
//var proxyUri = new Uri($"http://127.0.0.1:9000");
var webProxy = new WebProxy(proxyUri)
{
UseDefaultCredentials = false // 关键!不要发送windows系统凭据,否则容易403
};
if (!string.IsNullOrWhiteSpace(proxySettings.Account))
{
webProxy.Credentials = new NetworkCredential(
proxySettings.Account,
proxySettings.Password);
}
//无法伪造浏览器指纹, 被遭TLS JA3 指纹风控拦截
//var socketsHttpHandler = new SocketsHttpHandler
//{
// UseProxy = true,
// Proxy = webProxy,
// CookieContainer = Cookies,
// UseCookies = true,
// // 是否允许自动重定向
// AllowAutoRedirect = true,
// AutomaticDecompression = DecompressionMethods.All,
// PooledConnectionLifetime = TimeSpan.FromMinutes(5),
// ConnectTimeout = TimeSpan.FromSeconds(15),
// //// TLS 配置,解决WAF 403指纹拦截
// SslOptions = new SslClientAuthenticationOptions
// {
// // 强制TLS12,很多CDN/WAF对TLS1.3的.NET指纹拦截报403
// EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13,
// //EnabledSslProtocols = SslProtocols.Tls12,
// //EnabledSslProtocols = SslProtocols.Tls13,
// //CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
// //// 忽略证书(本地抓包代理调试用,生产务必关闭!)
// //RemoteCertificateValidationCallback = (object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) =>
// //{
// // LogHelpter.AddLog(
// // $"TLS debug:errors={sslPolicyErrors}; subject={certificate?.Subject}",
// // fileNamePrefix: LogFileNamePrefixEnum.login_error.ToString());
// // // 调试:return true;
// // return sslPolicyErrors == SslPolicyErrors.None;
// //}
// },
//};
//===================设置代理2============
//// 1. 确保已下载好dll ,windows使用tls-client.dll,linux使用tls-client.so,这两个文件需要放到执行根目录中
//EnsureLibraryExistsAsync 会检查是否有更新或缺少的文件,会自动下载需要的tls-client.dll,生产环境建议是自己先下好放到根目录
//var task = TlsLibraryLoader.EnsureLibraryExistsAsync();
//task.Wait();
// 2.为处理程序指定一个特定的浏览器标识符进行初始化
var tlsClientHandler = new TlsClientHandler
{
TlsClientIdentifier = ClientIdentifier.Chrome133,
//代理设置
Proxy = webProxy,
};
_http = new HttpClient(tlsClientHandler)
{
Timeout = TimeSpan.FromSeconds(timeoutSeconds)
};
}
_http.DefaultRequestHeaders.Accept.ParseAdd("application/json, text/plain, */*");
_http.DefaultRequestHeaders.UserAgent.ParseAdd(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36");
//_http.DefaultRequestHeaders.TryAddWithoutValidation("Host", "gg.vip");
_http.DefaultRequestHeaders.Referrer = new Uri("https://gg.vip/");
_http.DefaultRequestHeaders.TryAddWithoutValidation("Origin", "https://gg.vip");
_http.DefaultRequestHeaders.AcceptEncoding.Clear();
_http.DefaultRequestHeaders.TryAddWithoutValidation("accept-encoding", "gzip, deflate, br, zstd");
_http.DefaultRequestHeaders.TryAddWithoutValidation("accept-language", "zh-CN,zh;q=0.9");
}
/// <summary>
/// 执行 Login Async 的处理逻辑。
/// </summary>
/// <param name="username">username 参数。</param>
/// <param name="password">password 参数。</param>
/// <param name="lang">lang 参数。</param>
/// <param name="algorithm">algorithm 参数。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>表示异步操作结果的任务。</returns>
public async Task<JsonObject> LoginAsync(
string username,
string password,
string lang,
LoginAlgorithm algorithm,
CancellationToken cancellationToken)
{
// 方法流程:保留原有处理顺序,避免影响协议交互和外部行为。
var logicalPayload = new JsonObject
{
["user_name"] = username,
["user_pass"] = password,
["lang"] = NormalizeLang(lang)
};
using var response = await SendLoginRequestAsync(
logicalPayload,
algorithm,
cancellationToken);
var raw = await response.Content.ReadAsStringAsync(cancellationToken);
// LogHelpter.AddLog($"登录返回原始数据:{raw}", fileNamePrefix: LogFileNamePrefixEnum.login.ToString());
if (string.IsNullOrWhiteSpace(raw))
{
return new JsonObject
{
["code"] = (int)response.StatusCode,
["msg"] = response.ReasonPhrase ?? "empty response",
["data"] = ""
};
}
JsonNode? rawNode;
try
{
rawNode = JsonNode.Parse(raw);
}
catch
{
return new JsonObject
{
["code"] = (int)response.StatusCode,
["msg"] = response.ReasonPhrase ?? "non-json response",
["data"] = raw
};
}
return new JsonObject
{
["code"] = (int)response.StatusCode,
["msg"] = response.ReasonPhrase ?? "unexpected response",
["data"] = decrypted?.DeepClone()
};
}
private async Task<HttpResponseMessage> SendLoginRequestAsync(
JsonObject logicalPayload,
LoginAlgorithm algorithm,
CancellationToken cancellationToken)
{
var body = "{\"PacketType\":\"TableGameStatus\",\"WebsiteId\":7,\"WebSiteTableId\":\"P021\",\"State\":1}";
using var request = new HttpRequestMessage(HttpMethod.Post, new Uri( "https://test.gg/api/login"))
{
Content = new StringContent(body, Encoding.UTF8, "application/json")
};
// HTTP 代理通常通过 CONNECT 建立 TLS 隧道,先明确使用 HTTP/1.1,
// 避免把直连时的 HTTP/3 协商行为带到代理链路中。
request.Version = _usingProxy
? HttpVersion.Version11
: HttpVersion.Version30;
request.VersionPolicy = _usingProxy
? HttpVersionPolicy.RequestVersionExact
: HttpVersionPolicy.RequestVersionOrLower;
request.Content.Headers.Remove("Content-Type");
request.Content.Headers.TryAddWithoutValidation("Content-Type", "application/json;charset=UTF-8");
using var requestTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
requestTimeout.CancelAfter(TimeSpan.FromSeconds(12));
try
{
var response = await _http.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead,
requestTimeout.Token);
if (!response.IsSuccessStatusCode)
{
// 请求失败
// await LogUnexpectedResponseAsync(response, requestTimeout.Token);
}
// Axios treats non-2xx responses as failures and retries once.
if (response.IsSuccessStatusCode || attempt == 1)
{
return response;
}
response.Dispose();
}
catch (HttpRequestException) when (attempt == 0)
{
// Retry transport failures once, matching the browser wrapper.
}
catch (OperationCanceledException) when (
attempt == 0 && !cancellationToken.IsCancellationRequested)
{
// Retry a per-request timeout, but preserve caller cancellation.
}
throw new HttpRequestException("The login request failed after one retry.");
}
/// <summary>
/// 释放当前对象占用的资源。
/// </summary>
public void Dispose() => _http.Dispose();
}
}
tls-client.dll 下载地址:
下载好的tls-client.dll文件不管下的文件名是啥,都需要改为 tls-client.dll 放入程序执行根目录中,tls-client.so一样。

https://github.com/bogdanfinn/tls-client/releases
tls-client.so下载地址:
https://github.com/bogdanfinn/tls-client/releases
tls-client.dll 、tls-client.so 网盘下载地址,版本 v1.15.1:
通过网盘分享的文件:httpClient模拟TLS指纹数据
链接: https://pan.baidu.com/s/12OZj9OGGrsfT_ZIchMx3_A?pwd=247d 提取码: 247d