Uw betrouwbare partner voor (mobiele) web applicaties
TwitterEmailRSS

Certificate Pinning Plugin for PhoneGap to prevent Man in the Middle Attacks

A while ago my colleagues and I were working on a PhoneGap app which required a high level of security. Among other measures, we implemented certificate pinning to prevent Man in the Middle attacks. In this blog I’ll tell you what we’ve done and give you a link to a certificate pinning PhoneGap plugin I recently wrote.

Man in the Middle attackman-in-the-middle-attack

Ofcourse you have secured communication with an SSL certificate on the server. With a desktop browser, you will normally see the green certificate bar next to the URL. In a mobile app however, there is no such bar, so you won’t notice when it suddenly turns red because an attacker is impersonating the server with a self signed certificate. This may happen when f.i. you use the app via a compromised public WiFi hotspot. The attacker intercepts all traffic without the user noticing it.

Certificate pinning

A good way to make sure your app connects directly to your server, is by checking the fingerprint of the SSL certificate. In our app we implemented this purely in native code for iOS and Android and it works great; intercepting traffic via a proxy is no longer possible. (Note that we also encrypt the data itself, just in case this solution gets compromised.)

Native iOS and Android implementation

So what the code needs to do is fetch the certificate from the endpoint the app connects to and compare its fingerprint to a list of fingerprints your app allows to connect to. In Java, it looks a bit like this (simplified):

boolean isConnectionSecure(url, expectedFingerprint) {
  return expectedFingerprint.equals(getFingerprint(url));
}

String getFingerprint(String httpsURL) {
  HttpsURLConnection cnx = (HttpsURLConnection) new URL(httpsURL).openConnection();
  Certificate cert = cnx.getServerCertificate();
  MessageDigest md = MessageDigest.getInstance("SHA1");
  md.update(cert.getEncoded());
  return getHex(md.digest());
}

PhoneGap plugin

I’ve wanted to enable fellow PhoneGap developers to use this feature via a plugin and finally took the time to create the plugin. With the plugin, developers can create a Javascript call like this one to verify the connection with the server:

var server = "https://build.phonegap.com";
var fingerprint = "8F A5 FC 33 20 2D 45 B4 EC 95 87 F0 50 F0 18 14 DF 98 50 64"; // valid until sep 2014

window.plugins.sslCertificateChecker.check(
          successCallback,
          errorCallback,
          server,
          fingerprint);

Once the successCallback is invoked, you can be pretty sure there is no Man in the Middle attack going on.

The SSLCertificateChecker plugin can be found here, on Github.

What about PhoneGap Build?

PhoneGap Build is fully supported by the plugin.

Oh, and if you are using PhoneGap Build, I highly recommend our Buildmeister app, which will make your development cycle a bit shorter:

Android app on Google Play

Buildmeister - X-Services

4 thoughts on “Certificate Pinning Plugin for PhoneGap to prevent Man in the Middle Attacks

  1. Hi Eddy,

    this looks like a nice plugin, however discussing this at work we were wondering about the actual implementation. The certificate fingerprint check opens a new connection and checks the fingerprint. This ensures *this particular connection* is safe. But there is no guarantee that other connections the application might establish later to the same server will also be safe. Is this “good enough”? Would it not make sense to verify the fingerprint on each SSL handshake, or even on each HTTP request? Sorry, I am not an expert, but I can understand this concern about the current implementation. What do you think?

    Thanks,
    Jan

    • Hi Jan,

      I am aware of this limitation and thus agree with your concerns.

      What I’d like to do when I can find some time is adding the possibility to do actual HTTP calls via the plugin so the SSL cert can be checked on every request.

      For now you need to decide on your own at which point(s) during the app lifecycle you want to check the certificate. Maybe on every connection change, maybe before every request (doing the request in the callback of the plugin), or on startup / resume only.

      If you star/watch the repo you will get notified in case anything changes.

      Best,
      Eddy

      • Hi Eddy,
        thanks! We will consider performing the check on each request. Are you aware of any performance concerns with this approach (ios/Android)?
        Thanks,
        Jan

Comments are closed.