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

Xamarin Forms双端证书固定场景下SSL连接无法建立问题求助

Xamarin Forms双端证书固定功能SSL连接报错问题

我在Xamarin Forms的Android、iOS双端实现证书固定功能时,原有可正常运行的代码近期突然抛出错误:"The SSL connection could not be established, see inner exception."

相关代码

public static async Task<HttpResponseMessage> SendWebApiRequest(HttpRequestMessage msg)
{
    try
    {
        int timeout = 60;
        var handler = new HttpClientHandler
        {
            UseProxy = true,
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        };
        handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
        handler.ServerCertificateCustomValidationCallback = CheckCertificate;
        using (HttpClient client = new HttpClient(handler))
        {
            client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
            client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
            using (CancellationTokenSource cts = new CancellationTokenSource())
            {
                cts.CancelAfter(TimeSpan.FromSeconds(timeout));

                HttpResponseMessage reply = await client.SendAsync(msg, cts.Token);
                ProcessResponseStatus(reply);
                if (reply.StatusCode == HttpStatusCode.Unauthorized)
                    throw new InvalidOperationException("The authentication failed. Please logout and logback in with a valid account");

                return reply;
            }
        }
    }
    catch (InvalidOperationException) {
        throw new InvalidOperationException("There was an issue connecting with the server, please try again later or contact support.");
    }
    catch (WebApiServiceExceptions) { throw new WebApiServiceExceptions(WebApiServiceExceptionType.NoInternetAccess, "No internet connection detect! Please check your internet connection!"); }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        throw new Exception("There was an issue connecting with the server, please try again later or contact support.");
    }
}

private static bool CheckCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
{
    var publicKey = "MY PUBLIC KEY";
    return publicKey == certificate?.GetPublicKeyString();
}

各端错误详情

Android端

  • 错误信息:Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED
  • 堆栈跟踪:
at Mono.Net.Security.MobileAuthenticatedStream.ProcessAuthentication (System.Boolean runSynchronously, Mono.Net.Security.MonoSslAuthenticationOptions options, System.Threading.CancellationToken cancellationToken) [0x0025c] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System/Mono.Net.Security/MobileAuthenticatedStream.cs:310
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore (System.IO.Stream stream, System.Net.Security.SslClientAuthenticationOptions sslOptions, System.Threading.CancellationToken cancellationToken) [0x0007b] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corefx/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs:165

iOS端

  • 错误信息:The authentication or decryption has failed.
  • 堆栈跟踪:
at Mono.AppleTls.AppleTlsContext.EvaluateTrust () [0x000c7] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.AppleTls/AppleTlsContext.cs:307 
at Mono.AppleTls.AppleTlsContext.ProcessHandshake () [0x00075] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.AppleTls/AppleTlsContext.cs:213 
at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncOperationStatus status, System.Boolean renegotiate) [0x000da] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.Net.Security/MobileAuthenticatedStream.cs:715 
at Mono.Net.Security.AsyncHandshakeRequest.Run (Mono.Net.Security.AsyncOperationStatus status) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.Net.Security/AsyncProtocolRequest.cs:289 
at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (System.Threading.CancellationToken cancellationToken) [0x000fc] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System/Mono.Net.Security/AsyncProtocolRequest.cs:223

涉及的证书为Azure函数应用证书。


解决方案
  1. 更新硬编码的公钥
    Azure函数应用的证书默认开启自动轮转机制,有效期通常为1年,到期前会自动更新证书,公钥也会同步变更。你硬编码在CheckCertificate方法中的公钥已经和当前服务端证书公钥不匹配,是本次报错的核心原因。你可以通过浏览器访问Azure函数域名,导出当前证书的公钥字符串替换代码中的硬编码值即可临时恢复。

  2. 优化证书固定逻辑避免后续轮转失效
    不要只匹配叶子证书公钥,可同时固定中间CA和根CA的公钥,Azure默认使用DigiCert根证书,公钥长期不变,可避免单次叶子证书轮转导致功能失效。同时补充系统SSL错误校验逻辑,避免原有逻辑跳过系统校验带来的安全风险:

private static bool CheckCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
{
    // 先校验系统层面的SSL错误,无异常再做公钥匹配
    if (sslpolicyerrors != SslPolicyErrors.None)
    {
        return false;
    }
    // 建议改为匹配公钥哈希而不是完整公钥字符串,兼容性更好
    var allowedPublicKeys = new List<string> {
        "新的叶子证书公钥哈希",
        "Azure中间CA公钥哈希",
        "DigiCert根CA公钥哈希"
    };
    var certPublicKeyHash = certificate?.GetCertHashString();
    return allowedPublicKeys.Contains(certPublicKeyHash);
}
  1. 适配双端平台限制
  • Android 7.0以上系统默认不信任用户安装的证书,如果你使用的是自定义证书需要在AndroidManifest.xml中配置网络安全配置,明确信任对应域名的证书
  • iOS 14以上ATS策略要求TLS 1.2及以上版本,且证书必须符合苹果的证书要求,如果你固定的证书不符合ATS要求需要在Info.plist中配置对应域名的例外规则,确保证书校验能正常触发自定义回调
  1. 优化HttpClient实例管理
    原有代码每次请求都新建HttpClient实例,会导致大量端口占用,建议将HttpClient改为单例模式全局复用,避免不必要的资源消耗和连接异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 16:36:00