Building secure apps: Need help from app store operators

Communicating securely between a mobile app and a the corresponding backend is not a trivial task. Sure, nowadays we can write https and almost be certain our app is actually having encrypted communication with the right backend. However, just recently, I decided to do a communications check of apps on my iPhone using Fiddler as a proxy and was surprised to find that I could do a man-in-the-middle attack for an app I use regularly without the app noticing this. Apparently, the developers had opted to disable certificate validation (perhaps so the app would work with a developer backend that doesn’t have a pricey SSL server certificate installed) and forgot to turn it on again before publishing the app to the store.

However, there is an even better way to solve that problem that doesn’t involve buying an SSL server certificate. It’s called certificate pinning. Instead of relying on the operating system to check the validity of the presented server certificate by looking at its list of root certification authorities (which may contain entries the user is not aware of, see Superfish) developers can instruct their https calls to only accept a specific server certificate or, better yet, only certificates issued by a specific certification authority. This is not only much safer, it also avoids the costs of buying SSL server certificates.

So there we are, we have a method to ensure our app is talking to the right backend. The trickier part, though, is ensuring that whoever is making the call to our backend is actually who we think they are (i.e., our own app).

A simple approach to this problem would be to include an SSL client certificate in all requests to the backend, using a certificate whose private key is included as part of the app bundle. The problem with this is that it’s just not possible to hide the certificate well enough in our bundle to make it impossible to extract that certificate and its private key through reverse engineering. And since all clients would be using the same certificate, having that certificate compromised means we cannot tell if it’s acutally our app that is calling the backend.

The solution to this problem is to issue individual SSL client certificates to each device that is accessing the backend.

The vendors of Mobile Device Managament (MDM) software have great solutions that do exactly that. The problem is that these solutions can only be applied to devices that are in full control of the MDM solution. That’s great for internal apps on company devices but doesn’t help at all for apps you’re distributing to others.

Here is my proposal: App store operators should include a method to create an unique SSL client certificate upon installation of the app that is signed either using a certificate (public and private key) the app creator uploads into the app store or a certificate created by the app store vendor. This would make it very easy to check on the server side if a request is coming from an app that was actually distributed through the app store (and paid for, in the case of non-free apps) by using the signing certificate’s public key.

Such a feature could also be included in cloud backends like Azure Mobile Services where one could limit requests only to genuine apps and provide the corresponding functionality the client libraries accessing the backend.

All in all, this approach would greatly increase app communication security without much effort for the app developer. Now, how to convince the app store operators?


Serial communication using Reactive Extensions

The main purpose of Reactive Extensions (Rx) is to enable processing event streams. I set out to use Reactive Extensions for receiving data on the serial port and learned some new things.

Here is the code that uses Observable.FromEventPattern<T>() to create an IObservable<T> from the .NET event SerialPort.DataReceivedEvent:

The event does not actually contain any information on the data received, it only indicates that there is data available. Reading the data is done inside the lambda expression. Reading serial data will return a list of bytes. This list may contain a complete message or just a part of a message or even multiple messages. To handle this, I want the observable to be an IObservable<byte>, i.e., it will produce a raw stream of bytes without any indication of where a message begins or ends. This is done through the extension method public static IObservable<TResult> SelectMany<TSource, TResult>(this IObservable<TSource> source, Func<TSource, IEnumerable<TResult>> selector) that is used to flatten the sequence returned by the lambda.

So I now have a stream of bytes. I want these bytes to be chunked into messages. For my particular protocol, messages are separated by a special byte. Separation can be done in two ways:

Here, a new observable is created using Observable.Create(). This observable subscribes to the byte stream, collects the data in a local collection and fires OnNext() whenever a message delimiter is encountered.

This version uses the Scan() operator to achieve the same thing. The output is an IObservable<IEnumerable<byte>> that fires an IEnumerable<byte> for every new message.

This code worked well up until the point I started attaching multiple observers to the message stream, one to process the messages and one to just dump received messages to a debug console. What happened then was that the code in the first code sample was called multiple times: once for each subscriber. This meant that each chunk of serial data was only received by one subscriber, not all subscribers. There are two possible solutions to this: Either introduce a Subject<IEnumerable<byte>> subscribing to serialPortSource and have consumers subscribe to the subject or use the Publish() operator that does the work for you.

Creating a new observable that produces deserialized messages from the observable producing lists of bytes is now trivial using a simple Select().

What remains is the question of how to use the received data in a typical workflow of sending out a message and receiving a response in return. Here is an example:

This example uses the Replay() operator. Replay will capture all events from the observable that are fired after the call to Connect(). After calling Connect() the call is sent to the device at the other end of the serial connection. The second await filters the incoming messages for the desired message (even using a filter criterion that was not known before the request was sent), adds a timeout, uses FirstAsync() to return an observable that only returns the first element followed by OnCompleted(), and waits for that OnCompleted() using await. Since Replay() is capturing all messages, the following await call on the observable should consider all answers from the target, whether they are received before or after the second call to await.


ALM Days 2015: Mobile in the Enterprise