14

Currently I worked on Flurl and I tried to contact an API in https (I am in my lab). So the certificate is not valid and Flurl can't continue to work :/

Here is my error message:

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.

In Flurl documentation we can use using Flurl.Http.Configuration; and modify the DefaultHttpClientFactory However I do not understand the elements specified to say of jumped over the errors.

On the web I can see the same case: https://github.com/tmenier/Flurl/issues/365 Do you have an issue for this problem?

Thank you!

Digitag
  • 235
  • 3
  • 5
  • 11

3 Answers3

32

The most typical way to do this is to create a custom factory:

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

Then register it somewhere in your app startup:

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

Flurl reuses the same HttpClient instance per host by default, so configuring this way means that every call to theapi.com will allow the use of the untrusted cert. The advantage of this over passing an HttpClient to a FlurlClient constructor is that it keeps this configuration "off to the side" and works when you use Flurl in the more typical/less verbose way:

await "https://theapi.com/endpoint".GetJsonAsync();
Softlion
  • 12,281
  • 11
  • 58
  • 88
Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • 2
    Hi @ToddMenier thank you for this update. I only had to change the syntax. `public class UntrustedCertClientFactory : DefaultHttpClientFactory { public override HttpMessageHandler CreateMessageHandler() => new HttpClientHandler { ServerCertificateCustomValidationCallback = (a, b, c, d) => true }; }` – Digitag Dec 26 '18 at 08:48
  • @ToddMenier Is there any drawback to this change, perhaps client is vulnerable to attacks since bypassing Certificate validation callback, I am speculating – Morse Apr 02 '20 at 14:58
  • @Prateek The risks are exactly the same as doing it with a raw HttpClient. You'll need to determine whether it's appropriate for your situation. – Todd Menier Apr 02 '20 at 17:16
  • I would do this strictly for unit tests or else restrict it to development and testing environments. Once you're in production, SSL certificates should be in place, or you're asking for trouble. – Captain Kenpachi Aug 15 '20 at 18:47
6

Here is my setup for Flurl, which works with untrusted certificates:

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>();

I have created custom HttpClientHandler which accepts every certificate in ServerCertificateCustomValidationCallback. Of course, you can use other logic in this handler.

Update: With this setup, you cannot use Flurl extensions for URL (you cannot write "http://myadress.com/apiInfo".GetJsonAsync<ApiInfoDto>(). You have to create Flurl client as seen above and use Flurl client for your calls as demonstrated also in mine code. The usage is the same as Flurl extensions for URL.

Karel Kral
  • 5,297
  • 6
  • 40
  • 50
  • Hi Karel, thank you for your support. it is therefore necessary to modify the values of HttpClientHandler what Flurl generates by default. But your code is this present in the program class? Can you say me where apply this element? When you specify the new Uri is this the URL I am trying to contact? – Digitag Dec 20 '18 at 20:35
  • @Digitag See my updated answer. In the real program, I initialiatize FlUrlClient at program startup and save it in some variable or property that is globally accessible (i.e. some kind of service). And then use it in the application. – Karel Kral Dec 21 '18 at 10:21
  • 1
    @KarelKral This certainly works, but the alternative I've offered might have some advantages for you as well. – Todd Menier Dec 21 '18 at 13:26
4

An inline solution to accept any certificate is:


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();

With WithClient() you can pass a client configured different than the default client. In some cases you would not want to change the default client, but apply properties, e.g. the certificate validation only to this specific case.

lufist
  • 73
  • 1
  • 2
  • 9
  • 1
    Please provide a detailed explanation to your answer, in order for the next user to understand your answer better. – Elydasian Jul 28 '21 at 12:25