certificate_pinning_httpclient_plus
An implementation of Dart's HttpClient with certificate pinning against SPKI
(Subject Public Key Info) SHA-256 hashes.
Because it implements dart:io's HttpClient interface, it drops into anything
that accepts one — package:http's IOClient, Dio's IOHttpClientAdapter, or
direct dart:io usage.
Platform support
| Platform | Supported | Native implementation | Minimum version |
|---|---|---|---|
| Android | ✅ | HttpsURLConnection |
API 21 |
| iOS | ✅ | NSURLSession |
12.0 |
| macOS | ✅ | NSURLSession |
10.14 |
| Linux | ✅ | OpenSSL | — |
| Windows | ✅ | WinHTTP + CryptoAPI | 10 |
Linux build requirement: the plugin links against OpenSSL, so the development headers must be present on the build machine:
sudo apt-get install libssl-dev(Debian/Ubuntu) orsudo dnf install openssl-devel(Fedora).
macOS entitlement: sandboxed macOS apps cannot make outbound connections unless
com.apple.security.network.clientis set. Add it to bothmacos/Runner/DebugProfile.entitlementsandmacos/Runner/Release.entitlements—flutter createdoes not add it for you.<key>com.apple.security.network.client</key> <true/>
Android: the plugin's manifest already declares
INTERNETandACCESS_NETWORK_STATE, which are merged into your app.
Installation
dependencies:
certificate_pinning_httpclient_plus: ^1.0.0
Getting your pin
Pins are the base64-encoded SHA-256 digest of a certificate's SPKI. The client logs the SPKI hash of every certificate in the chain, so the simplest way to get yours is to make one request and read the log.
You can also compute it ahead of time with GnuTLS — look for the Public Key PIN line:
gnutls-cli --print-cert example.com
Or with OpenSSL:
openssl s_client -connect example.com:443 </dev/null 2>/dev/null \
| openssl x509 -pubkey -noout \
| openssl pkey -pubin -outform der \
| openssl dgst -sha256 -binary \
| openssl enc -base64
Usage
import 'package:certificate_pinning_httpclient_plus/certificate_pinning_httpclient_plus.dart';
const pins = ["S4kZuhQQ1DPcMOCYFQXD0gG+UW0zmyVx6roNWpRl65I="];
With dart:io
final client = CertificatePinningHttpClient(pins);
final request = await client.getUrl(Uri.parse("https://example.com"));
final response = await request.close();
With package:http
import 'package:http/io_client.dart';
final client = IOClient(CertificatePinningHttpClient(pins));
final response = await client.get(Uri.parse("https://example.com"));
With Dio
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
final dio = Dio();
dio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () => CertificatePinningHttpClient(pins),
);
Disabling logs in release builds
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
Logger.level = kDebugMode ? Level.debug : Level.nothing;
How it works
- On the first request to a host, the certificate chain is fetched natively via
a
MethodChanneland cached per host. - The SHA-256 digest of each certificate's SPKI is compared against your pins.
- Only the matching certificates are installed into a
SecurityContextas trusted certificates, and the request is made through anHttpClientbuilt on that context.
If no certificate matches, the security context trusts nothing and the connection fails. On a pinning failure the cached chain for that host is discarded, so a legitimate certificate rotation recovers on the next request while a MitM attempt keeps failing.
Pinning to a leaf certificate means requests break the moment that certificate rotates. Pin the intermediate, or supply several pins (current plus a backup), if you need rotation headroom.
Credits
This package is a maintained continuation of sebkoller/certificate_pinning_httpclient, which is no longer updated. It adds macOS, Linux and Windows support on top of the original Android and iOS implementations.
The Android and Apple native implementations originate from approov/approov-service-flutter-httpclient by CriticalBlue Ltd.
License
MIT — see LICENSE. Copyright notices for all upstream authors are retained there.
Libraries
- certificate_pinning_httpclient_plus
- An implementation of Dart's HttpClient with certificate pinning against SPKI (Subject Public Key Info) SHA-256 hashes.