grpc-dart icon indicating copy to clipboard operation
grpc-dart copied to clipboard

how to do SSL pinning?

Open YazeedAlKhalaf opened this issue 2 years ago • 1 comments

grpc version: 3.0.2

How can I implement SSL pinning? I would like to be able to tell the app to stop sending requests if it detects the certificate is not the expected one.

Let's say my server has a certificate called server-certificate and the attacked has a certificate called attacker-certificate. I would like to check if the certificate is server-certificate and if it is indeed I would like to allow the app to send the call.

If it detects that server-certificate is not used to send that request it should fail.

I want this to protect the app from MITM attacks that observe the requests.

The problem now is that I can't event see the traffic when proxying, so how can I proxy the traffic to mimic the attack and then implement SSL pinning to solve this problem.

The code that I tried using is the following:

final certificateByteData = await rootBundle.load(
      'assets/my-certificate.pem',
);
final certificateBytes = certificateByteData.buffer.asUint8List().toList();

var myChannel = ClientChannel(
  "MY-API-URL-HERE",
  port: 443,
  options: ChannelOptions(
    credentials: ChannelCredentials.secure(
      certificates: certificateBytes,
      onBadCertificate: (X509Certificate certificate, String host) {
        print("cert: $certificate");
        print("host: $host");
        return false;
      },
    ),
  ),
),

I would appreciate it if you could guide me in what to do to get this working.

Also it would be great if the documentation would cover this too.

YazeedAlKhalaf avatar Jun 01 '22 13:06 YazeedAlKhalaf

The problem now is that I can't event see the traffic when proxying

If you can't see the traffic it means your client detected invalid certificates and just droped connection Watch proxy logs for example:

127.0.0.1:55657: client connect
127.0.0.1:55657: server connect api.someapp.com:443 (1.2.3.4:443)
127.0.0.1:55657: Client TLS handshake failed. The client does not trust the proxy's certificate for api.someapp.com (OpenSSL Error([('SSL routines', '', 'sslv3 alert certificate unknown')]))
127.0.0.1:55657: client disconnect
127.0.0.1:55657: server disconnect api.someapp.com:443 (1.2.3.4:443)

how can I proxy the traffic to mimic the attack and then implement SSL pinning to solve this problem

Fastest / easiest way change these lines to this:

  SecurityContext? get securityContext {
    if (!isSecure) return null;

    final context = SecurityContext(withTrustedRoots: true);
    context.setAlpnProtocols(supportedAlpnProtocols, false);
    context.setTrustedCertificatesBytes(_certificateBytes!, password: _certificatePassword);
    return context;
  }

SecurityContext(withTrustedRoots: true) means your device will trust root certificates also and not just your provided one.

Now you have to add your proxy cert to Root certs on the device.

maRci002 avatar Jun 26 '22 19:06 maRci002