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

Game TV

I’ve been wanting to create a mobile videogame-focused app for a looooooooong time. During the Christmas break I finally has some spare time and created…: Game TV  😛 😮 🙂   sorry, can’t stop smiling

Game TV.. wut?

So what is it? By installing Game TV the user will always know which channel (game related websites or youtube channels, to be precise) has added new content. By clicking the channel, the user will see a list of recently added video’s and is able to play the video and share it with friends (email) or the world (twitter). Game TV doesn’t bother you with registration or advertisements, just pick and play!

Game TV at a glance

Technique

Well, we’re all techies here, right? So let’s highlight some technical bits.

Client

 PhoneGap / Cordova wrapped JQuery Mobile app (css3, html5, js). Kindly built by PhoneGap build. Notable stuff:

– Responsive design with CSS3 is cool. See the upper left screenshot in the pic above. This is how I position the video (block a) next to the description (block b)  when in landscape, or above the description when in portrait orientation (default JQM width of these blocks is 50%):

@media all and (orientation:portrait) {
  #videoplayer .ui-block-a, #videoplayer .ui-block-b {
    width: 100%;
  }
}

– As the app will *cough* obviously hit 100.000+ users shortly, clientside caching is very important. We cache the channels and videos in sessionstorage. But to guarantee a quick startup, we also leverage localstorage. When the app is started, the content is immediately retrieved from localstorage and asynchronously updated from the server, showing the diff to the user when done (red  count bubbles, we all know them).

– Since I want my app to be present in all appstores, I had to localise some bits of text. Keith Wood has created a simple yet very effective jquery localisation library.

Server

Play! Framework Java app, doing two things:

– Harvesting new content for all channels. 1 Job per channel.

– Serving the harvested content as JSON to the client.

What I’ve learned

– Android and iOS have great native videoplayers, as long as you invoke them correctly.

– Android animations are still not as smooth as on iOS. Fortunately, JQuery Mobile allows you to easily configure them per platform. I used this snippet:

// override some defaults, before jqm.js is loaded
$(document).bind("mobileinit", function(){
  $.mobile.defaultPageTransition = isAndroid() ? "fade" : "slide";
});

– Adding a Tweet button with a count bubble (see the upper left screenshot in the image above) is not as trivial as you’d think when you don’t want users to leave your app while tweeting. A combination of clickjacking, Twitter web intents and the PhoneGap Childbrowser plugin did the job.

– Some sites make life for a screenscraper really hard. Try to find the URL of the videos being played on this site for example. Horror!

– .. but YouTube rocks, thank you for providing easily parseable RSS feeds like this one (Gamespot channel).

– JQuery Mobile is great, but has some nasty caveats (stacking click handlers, document ready, reloading a page, etc). We’ll definitely blog about some high and lows of JQM in the future, but for now: download the Android app please please please 🙂There will probably be no iOS version because of the strict Apple review guidelines regarding streaming ‘protected’ content.

Hide iOS keyboard Form navigation buttons in PhoneGap / Cordova

iOS HTML keyboard with navigation bar

The default keyboard

You have probably seen this keyboard before: the default iOS keyboard that pops up for <input type=”tel”> form fields.

I don’t want those buttons!

The numeric keys are just fine, but the Previous/Next/Done buttons are not what I want when showing a page with only one input field. So… I wondered if the navigational buttons could be removed in my PhoneGap / Cordova HTML5 app.
iOS HTML keyboard without navigation bar

A solution 🙂

Fortunately, the internet is full of people who have similar problems, so a quick look around the globe revealed this great post.

UPDATE July 2013: simply adding this to your config.xml may get the trick done as well. BEWARE: it’s an app-wide setting, so if you need more fine grain control, read on. <preference name=”HideKeyboardFormAccessoryBar” value=”true”/>

But wait, there’s more!

This blog entry wouldn’t have existed if that was it. What I actually wanted, was an on demand solution; for one page show the buttonbar, and hide it on other pages.

Conditionally show or hide the navbar

What I wanted was controlling the appearance of the navigation bar based on a tag in the HTML. A custom class for the body tag seemed right, so I added this to the page for which the navigation bar should be hidden:

<body class="hideKeyboardNavBar">

So all I had to do was adjusting the piece of obj-c I added to my PhoneGap wrapper by checking for existence of the aforementioned classname:

NSString *hideForClass = @"hideKeyboardNavBar";

- (void)keyboardWillShow:(NSNotification*) notification {
  NSString *formClassName = [self.webView stringByEvaluatingJavaScriptFromString:@"document.body.className"];

  if ([formClassName isEqualToString:hideForClass]) {
    // remove the bar in the next runloop (not actually created at this point)
    [self performSelector:@selector(removeBar) withObject:nil afterDelay:0];
  }
}

The added code is on the highlighted lines: simply check whether or not the className of the body is equal to the className we hide the navigation bar for.

Question for the reader

I’m afraid the trick in the blogpost is as far as we can stretch the boundaries of the HTML keyboard on iOS devices. But… if anyone knows how to add a comma in the empty field below the 7, you’d be king.