Kotan Code 枯淡コード

In search of simple, elegant code

Menu Close

Struggling with SSL and Cloud-Backed Mobile Applications

While it is still certainly very common for mobile developers to build applications that stand on their own and do not communicate with the Internet, every day more and more mobile applications are released that are what we used to call “Smart Clients”. These apps sit on your mobile device (and are not browser apps or browser-shell apps). They might store data locally as a cache or back-up mechanism but the bulk of the application’s information comes from the Internet or, if you’re really upping the buzzword quota, the Cloud.

Let’s say you’re building a recipe application for mobile devices. This app is designed to let people access their recipes from any location so long as they have network data access. When you start the app, it queries a cloud-hosted server for your recipes and probably does so using some kind of secure authentication mechanism. Based on how a lot of cloud service providers are working lately, it’s very realistic to assume we’re doing Basic HTTP authentication over SSL.

Now we get into the real benefit of putting the data in the cloud – cross-platform access. I decide to write a Windows Phone 7 app and an iOS app. They both talk to the same recipe database and I should be able to share data among them seamlessly. Why would I do this? Because many people own a non-Apple phone and an iPad. Additionally, families often share service accounts where different family members have different mobile devices. Think Evernote here – they have apps for Mac, Windows, iPhone, iPad, Android – all access your shared, cloud-hosted store of notes.

Here’s the rub, the sticky bits, the source of the last 3 nights of frustration for me: not all services provided in the cloud surface clean, valid SSL certificates.

What does that mean? It means that when you make HTTP requests over SSL from an SDK, you are at the mercy of the limitations of that SDK. For example, if I am writing a desktop or server application in .NET and I know that a cloud database I’m talking to has SSL certs that don’t match their host names, I just write code that looks like this to manually override the cert validation:

ServicePointManager.ServerCertificateValidationCallback =
    ((sender, certificate, chain, sslPolicyErrors) => true);

I can put conditional logic in there to only let certain certificates from certain hosts go through, but you get the idea. Bottom line is I have some back-up plan where I can write code to counteract what most people consider “bad net citizenship” (SSL certs that trigger warnings or worse, fail outright).

What about with iOS? What happens if my iPhone application runs into a bad SSL certificate. Again, I should not have to write this kind of code, but it is possible. When you are picking your cloud service providers, I would add a lot of extra weight to providers whose data comes through on clean SSL certs.

Here’s the juicy part of the iOS code (part of an NSURLConnection delegate class) that manually overrides the SSL cert by responding to an authorization challenge:

- (BOOL)connection:(NSURLConnection *)connection
   canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    NSString *challenge = [protectionSpace challenge];
    if ([challenge isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        return YES;
    }
}

- (void)connection:(NSURLConnection *)connection
    didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    NSURLCredential *credential = nil;
    NSURLProtectionSpace *protectionSpace;
    SecTrustRef trust;

    protectionSpace = [challenge protectionSpace];
    trust = [protectionSpace serverTrust];
    credential = [NSURLCredential credentialForTrust:trust];

    // say "yes" to everybody... Note, this is BAD
    [[challenge sender] useCredential:credential
          forAuthenticationChallenge:challenge];
}

Why do I say this is bad? Well, the whole point of an SSL certificate is to establish a secure connection between you and the remote server. If someone gets between you and the remote server (called a man-in-the-middle attack) they can do all kinds of nasty crap to your data and, because you’ve written the above code, they might be able to get away with it.

But let’s say that you’re willing to accept that risk and you plow on. So now you decide to write a Windows Phone 7 app that reads from the same cloud database. Your code fails because the SSL cert doesn’t match the host name (again, this is a really common problem when cloud hosts do things to support massive numbers of clients). Well, you just use the ServicePointManager class like you did with the desktop .NET app, right? Ooops. No, actually, you’re utterly screwed. No such class exists in the WP7 SDK. In fact, there is absolutely no way in WP7 to override the validation of SSL certificates. In short, if an SSL cert chain fails and your WP7 app is on the client side of it, your app will not be able to talk to the remote server.

Case in point: I’ve been doing some experimenting with hosting an instance of CouchDB on Cloudant as an add-on to an application hosted in AppHarbor. This is great and they give you a nice SSL URL with a username and password embedded so that you can do awesome JSON goodness with CouchDB’s HTTP API. However. The certs from Cloudant fail validation on both iOS and WP7. About the only place it doesn’t fail validation is when using curl from the command line. If you’re using iOS you’ll be forced to hack around the SSL cert validation. If you’re using WP7, you’ll be totally boned.

So, what are the key points I want you to take away from this blog?

  1. If you’re using WP7, complain and never stop complaining until the folks at Microsoft catch up to all the other mobile operating systems and actually give us the ability to intercept auth challenges in the cert chain. Not having the ability to override SSL validation in a WP7 app is assinine. I realize that MS wants us all to be secure, but for the love of all that is good, even Apple allowed us to have this ability, and they are notoriously paranoid about mobile security.
  2. E-mail, phone, or smoke-signal the provider of your cloud service and complain that their SSL certs aren’t good enough. Many of them will have a facility that will let you use your own certificate purchased from one of the authorities on both Microsoft and Apple’s root authority whitelist, but that won’t fix the host name problem. If you are comparing two providers (e.g. two hosts of CouchDB) and one has certs that fail and the other doesn’t, definitely give more weight to the one with good certs.

Again, this is not a pandemic or a problem that affects the entire universe. This problem only occurs when you’re trying to access resources over SSL from mobile devices and the SSL certificate fails validation. This validation failure happens a lot when hosts do creative things with their certificates and their host names. If this applies to your host, give them a call or an e-mail and see if they have workarounds available. The last thing you want to do is write your own proxy to compensate for bad certs, because that’s just going to make the gap between your proxy and the cloud host as vulnerable to MITM attacks as your mobile device would be without the proxy.

So, go forth and consume cloud resources over SSL – just make sure your mobile SDK can override bad certs or your cloud provider has ways of making the certs look valid.