You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core API间客户端与服务端第三方证书认证实现报错排查

.NET Core 证书认证故障修复方案

现有代码核心问题

  • 客户端重复创建HttpClient实例,提前配置了客户端证书的HttpClientHandler未绑定到实际发请求的客户端,证书没有随请求发送
  • 客户端调用GetRawCertDataString()获取的是证书原始数据的十六进制字符串,服务端用URL解码+直接构造证书的逻辑完全不匹配,直接抛出异常
  • 客户端判断证书为空的分支存在空引用错误:HttpActionContext被赋值为null后直接操作Response属性,会直接触发空指针异常
  • 服务端校验逻辑错误:将客户端证书指纹与服务端本地pfx证书指纹比对,除非客户端和服务端用的是同一张证书,否则校验永远不通过

修复代码

客户端控制器逻辑

[HttpGet]    
public async Task<List<WeatherForecast>> Get()
{
    List<WeatherForecast> weatherForecastList = new List<WeatherForecast>();
    X509Certificate2 clientCert = Authentication.GetClientCertificate();
    if (clientCert == null)
    {
        // 修复空引用问题,直接返回403即可
        return Forbid("Client Certificate Required");
    }
    // 配置Handler后直接用该Handler创建HttpClient,不要重复实例化
    HttpClientHandler requestHandler = new HttpClientHandler();
    requestHandler.ClientCertificates.Add(clientCert);
    requestHandler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
    
    using (var httpClient = new HttpClient(requestHandler))
    {
        var request = new HttpRequestMessage()
        {
            RequestUri = new Uri("https://localhost:44386/ServerAPI"),
            Method = HttpMethod.Get,
        };
        // 转Base64传输,避免十六进制转码问题
        request.Headers.Add("X-ARR-ClientCert", Convert.ToBase64String(clientCert.GetRawCertData()));
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        using (var response = await httpClient.SendAsync(request))
        {
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                string apiResposne = await response.Content.ReadAsStringAsync();
                weatherForecastList = JsonConvert.DeserializeObject<List<WeatherForecast>>(apiResposne);
            }
        }
    }
    return weatherForecastList;
}

服务端API逻辑

[HttpGet]
public IEnumerable<WeatherForecast> Getcertdata()
{
    IHeaderDictionary headers = base.Request.Headers;
    X509Certificate2 clientCertificate = null;
    string certHeaderString = headers["X-ARR-ClientCert"];

    if (!string.IsNullOrEmpty(certHeaderString))
    { 
        // 先转Base64为字节数组再构造证书
        byte[] certBytes = Convert.FromBase64String(certHeaderString);
        clientCertificate = new X509Certificate2(certBytes);                
        // 替换为你信任的客户端证书指纹,不要和服务端pfx比对
        var trustedClientCertThumbprint = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
        if (clientCertificate.Thumbprint.Equals(trustedClientCertThumbprint, StringComparison.OrdinalIgnoreCase))
        {
            // 校验通过逻辑
        }
        else
        {
            // 校验不通过返回403
            Response.StatusCode = 403;
            return Array.Empty<WeatherForecast>();
        }
    }
    else
    {
        Response.StatusCode = 403;
        return Array.Empty<WeatherForecast>();
    }

    var rng = new Random();
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)]
    }).ToArray();
}

优化建议

  • 不要每次请求都新建HttpClient,建议通过依赖注入注入IHttpClientFactory来创建客户端,避免端口耗尽问题
  • 生产环境不要禁用服务端证书校验,也就是不要写ServerCertificateCustomValidationCallback直接返回true的逻辑
  • 有条件的话直接用.NET Core内置的证书认证中间件来实现校验,不需要自己在接口逻辑里处理头解析,安全性和稳定性更高

内容的提问来源于stack exchange,提问作者mohan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:54:04