Flurl和不受信任的证书

15

我目前正在使用Flurl,并尝试联系一个https API(我在实验室里)。

由于证书无效,Flurl无法继续工作 :/

这是我的错误消息:

Unhandled Exception: System.AggregateException: One or more errors occurred. (Call failed. The SSL connection could not be established, see inner exception. POST https://IP/api/aaaLogin.json) ---> Flurl.Http.FlurlHttpException: Call failed. The SSL connection could not be established, see inner exception. POST https://IP/api/aaaLogin.json ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
在Flurl文档中,我们可以使用using Flurl.Http.Configuration;并修改DefaultHttpClientFactory。然而,我不理解所指定的元素以及如何处理错误。在网上,我看到了相同的情况:https://github.com/tmenier/Flurl/issues/365。您是否有关于这个问题的解决方案?谢谢!
3个回答

33

最典型的方法是创建自定义工厂

public class UntrustedCertClientFactory : DefaultHttpClientFactory
{
    public override HttpMessageHandler CreateMessageHandler() {
        return new HttpClientHandler {
            ServerCertificateCustomValidationCallback = (_, _, _, _) => true
        };
    }
}

然后在你的应用程序启动时的某个地方进行注册:

FlurlHttp.ConfigureClient("https://theapi.com", cli =>
    cli.Settings.HttpClientFactory = new UntrustedCertClientFactory());

默认情况下,Flurl会重用同一主机的HttpClient实例,因此以这种方式进行配置意味着对theapi.com的每个调用都将允许使用不受信任的证书。相比于将HttpClient传递给FlurlClient构造函数的方法,其优点在于将此配置“放到了一边”,并且在您以更典型/更简洁的方式使用Flurl时可以正常工作。

await "https://theapi.com/endpoint".GetJsonAsync();

2
嗨@ToddMenier,感谢您的更新。我只需要更改语法。public class UntrustedCertClientFactory:DefaultHttpClientFactory { public override HttpMessageHandler CreateMessageHandler()=> new HttpClientHandler { ServerCertificateCustomValidationCallback =(a,b,c,d)=> true }; } - Digitag
@ToddMenier 这种更改是否存在任何缺点,例如客户端容易受到攻击,因为绕过了证书验证回调,我正在推测。 - Morse
@Prateek 风险与使用原始的 HttpClient 相同。您需要确定它是否适合您的情况。 - Todd Menier
我会将此严格限制在单元测试中,或者仅限于开发和测试环境。一旦进入生产环境,SSL证书应该已经安装好,否则会引起麻烦。 - Captain Kenpachi

6

以下是我针对Flurl的设置,可以与不受信任的证书一起使用:

HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, 
  errors) => true;
HttpClient httpClient = new HttpClient(httpClientHandler);
httpClient.BaseAddress = new Uri("https://myaddress.com");
var flurlClient = new FlurlClient(httpClient);

var apiInfo = await flurlClient.Request("apiInfo").GetJsonAsync<ApiInfoDto>();

我创建了自定义的HttpClientHandler,该处理程序接受在ServerCertificateCustomValidationCallback中的所有证书。当然,您可以在此处理程序中使用其他逻辑。

更新: 使用此设置,您不能使用Flurl扩展来处理URL(例如无法编写"http://myadress.com/apiInfo".GetJsonAsync<ApiInfoDto>())。 您必须像上面所示创建Flurl客户端,并在调用时使用Flurl客户端,就像我的代码演示的那样。使用方式与Flurl URL扩展相同。


嗨Karel,感谢您的支持。因此需要修改HttpClientHandler的值,这是Flurl默认生成的。 但是您的代码是否存在于程序类中?您能告诉我在哪里应用这个元素吗?当您指定新的Uri时,这是我要联系的URL吗? - Digitag
@Digitag 请看我的更新答案。在实际程序中,我会在程序启动时初始化FlUrlClient并将其保存在全局可访问的某个变量或属性(即某种服务)中,然后在应用程序中使用它。 - Karel Kral
1
@KarelKral 这个肯定可以用,但是我提供的另一种选择对你也可能有一些优势。 - Todd Menier

4

接受任何证书的内联解决方案是:


var myString = await "https://some-server-with-an-invalid-cert.net"
    .AppendPathSegment("/some-file.txt")
    .WithClient(new FlurlClient(new HttpClient(new HttpClientHandler
              {
                  ServerCertificateCustomValidationCallback = (message, cert, chain,
                                                               errors) => true
              })))
    .GetStringAsync();

使用WithClient(),您可以传递配置不同于默认客户端的客户端。在某些情况下,您可能不想更改默认客户端,而是仅将属性应用于特定情况,例如仅对证书验证。


1
请提供您的答案的详细说明,以便下一个用户更好地理解您的答案。 - Elydasian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接