dio icon indicating copy to clipboard operation
dio copied to clipboard

fix(pinning): add callback for leaf certificate for better pinning

Open timshadel opened this issue 3 years ago • 1 comments

New Pull Request Checklist

  • [X] I have read the Documentation
  • [X] I have searched for a similar pull request in the project and found none
  • [X] I have updated this branch with the latest develop to avoid conflicts (via merge from master or rebase)
  • [X] I have added the required tests to prove the fix/feature I am adding
  • [X] I have updated the documentation (if necessary)
  • [X] I have run the tests and they pass

Pull Request Description

There are debates about the usefulness of certificate or public key pinning. It is required at many major companies. If someone chooses to do it then they need access to a leaf certificate.

The existing recommendations on certificate verification don't provide a leaf certificate for the request.

All of the following are insufficient.

  1. Add a certificate to the SecureContext
  2. Use badCertificateCallback
  3. Use the http_cert_pinning package

First. When you add a cert to the SecureContext, it will only check it against the root certificate. This means that you're going to declare trust in DigiCert or AWS or your self-signed cert. This works for a self-signed cert, but for all others this means that any middle man with a cert from your same provider can hijack your traffic.

Second. As my new test shows, badCertificateCallback does not return a leaf certificate. Instead it returns one higher up the chain. That often means that you're pinning to an AWS or other authority, and not the leaf certificate made specifically for your server.

Third. The http_cert_pinning package doesn't actually do anything with the certificates that Dio is handling. Instead, it maintains a cache of domains which it has separately tested against a list of certificate fingerprints it was given. When a request comes in, the plugin looks at the requested host, and simply asks the package if it ever checked that domain to see if the package got the correct certificates. It doesn't actually look at the certificates from this connection in Dio.

The problem stems from Dart itself.

As you can see, there is an open issue for Dart complaining that the badCertificateCallback doesn't return a leaf certificate. But one of the commenters found a workaround, and left some instructions on how to get the correct certificate.

That comment was very easy to apply to the DefaultHttpRequestAdapter. It simply adds one more callback at the right place in the response processing. If it isn't used, the request continues as expected. As my tests show, it properly delivers the leaf certificate to the callback where users can decide on the methods they want to use to approve or reject a certificate. The tests also show that badCertificateCallback does not return the leaf certificate.

Please consider adding this so that we may get one step closer to implementing full certificate pinning in pure Dart.

timshadel avatar Aug 20 '22 22:08 timshadel

It would be great to have this

allanwolski-openco avatar Sep 05 '22 20:09 allanwolski-openco

Hi @timshadel , I saw a package that does similar things: https://github.com/diefferson/http_certificate_pinning, can you identify the difference between your PR and the plugin? Thanks.

AlexV525 avatar Dec 14 '22 05:12 AlexV525

Hi everyone! We've made our hardfork repo public and published a new version of dio, named diox. The new package contains the PR of the fix. Please refer to https://pub.dev/packages/diox/versions/5.0.0-dev.1 to use the fork. You can also see why we're working for a hardfork at https://github.com/cfug/diox/issues/29 and https://github.com/flutterchina/dio/issues/1607.

AlexV525 avatar Dec 18 '22 15:12 AlexV525