bezzad / Downloader

Fast, cross-platform and reliable multipart downloader with asynchronous progress events for .NET applications.
MIT License
1.25k stars 193 forks source link

ExceptionHelper.CertificateValidationCallBack() is never called when compiling for android #144

Open csm101 opened 1 year ago

csm101 commented 1 year ago

I am trying to use Downloader in a NET7 app targeting android to download a file from a server using a self signed certificate.

everything is fine if I try the code in a NUnit test running in windows, but the Android implementation of .net totally ignores ServicePointManager.ServerCertificateValidationCallback.

Moreover: it would be nice to have a "ServerCertificateValidationCallback" event handler exposed by Downloader, in order to provide our own certificate validation without having to mess with system static global callbacks

bezzad commented 1 year ago

I came across an issue related to Xamarin-Android on GitHub link provided and it suggested a solution. You can try adding the following code to your app to see if it resolves the problem:

var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; //no SSL check needed yet

You can customize the return statement with your own verification codes later. If this helps to solve the issue, please let me know so that I can update the library accordingly. Thank you.

csm101 commented 1 year ago

Hi, That two lines you found you found are not sufficient: it doesn't set a global SSL handler that will be used transparently by the whole application.

I am already using that technique in other parts of my app that are communicating with the same server (it is also a rest server), but the client handler created that way needs to be explicitly used for constructing the HttpClient instance you are going to use: this is taken from my working code (simplified a little bit)

public static HttpClient CreateHttpClient()
{
   var handler = new HttpClientHandler();
   handler.ServerCertificateCustomValidationCallback += MyInternalValidateCertificate;
   result = new HttpClient(handler); // the handler has effect only for HttpClients created this way
}

I think (this is my personal interpretation) that the whole point is that they removed any global callback that can be used to disable application-wide SSL certificate checking, because it is a serious security threat that can be exploited by any public library you add to your application.

For example even your Downloader library actually is a security threat because it makes, application-wide, any self signed certificate a valid certificate. My application is also used to accept credit card payments (it is used also as a mobile pos) and actually, after Downloader gets instantiated at least once, I get installed a validation algorithm that blindly trust any self signed certificate. This means that from this moment any malicious server could impersonate the payment gateway of a bank by simply using a self signed certificate.

Because of this, I tried to change your library in order to make me decide when and IF to use a custom validation callback, by removing the one included in ExceptionHelper and adding a dedicated property to downloader configuration. It is not that complicated, these are the changes I had to do:

// this one in Request.cs
private HttpWebRequest GetRequest(string method)
{
   HttpWebRequest request = WebRequest.CreateHttp(Address);
   if (_configuration.ServerCertificateValidationCallback != null) // << this code
      request.ServerCertificateValidationCallback = +_configuration.ServerCertificateValidationCallback; << this code

// and this one in RequestConfiguration.cs
  ...
  public RemoteCertificateValidationCallback ServerCertificateValidationCallback { get; set; }
  ....

This does the trick, at least for windows apps, but still doesn't work under android. I think that the problem is that HttpWebRequest is now deprecated and they are not supporting this feature under Android, since it should all be reimplemented using HttpClient...

For the moment I gave up using Downloader, and I just implemented the resuming of the partial dowload myself (I didn't really neead parallel chunked download, even if it was nice to have).

I will wait for a version of Downloader that uses HttpClient, since I have seen it is already in your to-do list.

I think that in your HttpClient version you should provide a "CreateHttpClient" callback, so users will be able to implement an handler callback that creates a client using their own HttplClientHandler.

Thank you and have a nice day. Excellent work anyway.

bezzad commented 1 year ago

Yes @csm101, I trying to move the Downloader to the use of HttpClient. This is in progress and will be completed as soon as possible. Thanks for your feedback.