System.AggregateException 在 Xamarin.Forms Android 上尝试访问服务器时抛出

System.AggregateException thrown when trying to access server on Xamarin.Forms Android

我使用 HttpClient 与我的服务器通信,如下所示:

private static readonly HttpClientHandler Handler = new HttpClientHandler
                                                                 {
                                                                     AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip,
                                                                     AllowAutoRedirect      = true,
                                                                 };
    
private static readonly HttpClient Client = new HttpClient(Handler, false);

问题是我在 Android 上遇到 System.AggregateException 异常。异常详细信息可以在下面的屏幕截图中看到:

不过,应用程序在 iOS 上运行得非常好。

服务器正在使用 Let's Encrypt 证书,问题在一周前更新证书后才出现。

我已经检查了有关证书有效性的任何内容(过期、DNS 名称等),一切似乎都正常。

这是 Xamarin.Android 中的一个长期存在的问题 #6351,由 LetsEncrypt 的根目录到期并移动到新的根目录引起。

下面是 my post in that issue 的副本,解释了这种情况和解决方法。有关解决方法的详细信息,请参阅该线程中的其他帖子。


Scott Helme 对情况进行了精彩的描述。先去阅读它,然后我将描述(我认为)它如何适用于 xamarin-android.

我要复制那篇文章的关键图 (source):

红链过去经常发生:IdenTrust DST Root CA X3 是一个旧的根证书,几乎在任何地方都受信任,包括从 2.3.6 开始的 Android 设备。这就是 LetsEncrypt 曾经用作他们的根,这意味着每个人都信任他们。然而,这个 IdenTrust DST Root CA X3 最近过期了,这意味着一堆设备不会信任任何由它签名的东西。 LetsEncrypt 需要移动到他们自己的根证书。

蓝色链是理想的新证书——ISRG Root X1 是 LetsEncrypt 自己的根证书,包含在 Android 7.1.1+ 中。 Android 设备 >= 7.1.1 将信任已由此 ISRG Root X1 签名的证书。

但是,问题是旧的 7.1.1 之前的 Android 设备不了解 ISRG Root X1,并且不信任它。

LetsEncrypt 使用的解决方法是旧 Android 设备不检查根证书是否已过期。因此,它们默认提供一个链,其中包括 LetsEncrypt 的根 ISRG Root X1 证书(最新设备信任),但也包括来自现已过期的 IdenTrust DST Root CA X3 的签名。这意味着旧 Android 设备信任该链(因为它们信任 IdenTrust DST Root CA X3,并且不检查它是否已过期),而较新的设备也信任该链(因为它们能够计算出即使链的根已经过期,他们仍然相信中间的 ISRG Root X1 证书本身就是一个有效的根,因此信任它。

这是绿色路径,LetsEncrypt 目前默认服务的路径。

但是,xamarin-android 使用的 BoringSSL 库不是 Android 的 SSL 库。它 1) 不信任 IdenTrust DST Root CA X3,因为它已过期,并且 2) 不够聪明,无法确定它确实信任也在链中的 ISRG Root X1。因此,如果您为上图中的绿色链提供服务,它不会信任它。嘎嘎

因此选项是:

  1. 不要使用 BoringSSL,而要使用 Android 的 SSL 库。这意味着 xamarin-android 的行为与其他 Android 应用程序相同,并且信任过期的根。这是通过使用 AndroidClientHandler 完成的,如前所述。这应该修复 Android >= 2.3.6.
  2. 请使用 BoringSSL,但从 Android 的信任库中删除过期的 IdenTrust DST Root CA X3(设置中的“Digital Signature Trust Co. - DST Root CA X3”)。这会诱使 BoringSSL 在它信任的 ISRG Root X1 处停止其链(在 Android 7.1.1+ 上)。但是,这仅适用于 Android 信任 ISRG Root X1 的设备,即 7.1.1+。
  3. 一定要使用 BoringSSL,并使用 --preferred-chain "ISRG Root X1" 更改您的服务器以服务以 ISRG Root X1 为根的链,而不是过期的 IdenTrust DST Root CA X3(上图中的蓝色链) .这意味着 BoringSSL 完全忽略了 IdenTrust DST 根 CA X3,并根到 ISRG 根 X1。这同样只适用于信任 ISRG Root X1 的 Android 设备,即 7.1.1+.
  4. 与 3 相同,但通过手动编辑 fullchain.pem。
  5. 使用另一个 CA,例如 ZeroSSL,它使用可回溯到 Android 2.2 的根,并且在 2038 年之前不会过期。