This post originally appeared on IBM's Mobile Frontier blog on August 26th, 2013. I wrote this post to share some of our hurdles and solutions when developing hybrid apps.
I want to take some time today to discuss developing an Android app with Apache Cordova (a platform for developing hybrid mobile apps using HTML, CSS and JavaScript technologies). Specifically, a way to work more flexibly with certificates when using Cordova as a platform for development. If you currently use Cordova for development, you may be aware that dealing with self-signed, untrusted or invalid certificates (SSUICs) is a problem when writing an application that needs to contact some other entity via an internet connection (which is a very large percentage of mobile apps). Cordova has an implementation that, while secure, isn't inherently flexible. As you can see from the code below, if the Android app isn't built using debug mode, the connection is rejected without prompting or alerting the user if an SSUIC is presented during the connection process.
In the real world, shipping an app in 'debug' mode simply isn't going to fly. This becomes a problem when attempting to process a connection request and being presented with an SSUIC. Without modification to the above code, users must have a valid certificate available in order for the connection attempt to be successful. As is sometimes the case, you our your users may want to connect to an entity that is not set up with a valid certificate. A few solutions exist to help us work around or solve this problem. The first is an implementation which I don't ever want to see or hear about in production code. I have seen several blogs and forums suggest that developers simply write code to simply bypass the SSL Error and 'accept' all SSUICs. I don't think I need to go into detail on why this is bad idea - avoid this route at any cost. Our second option is more feasible, but still not ideal. It involves modifying and maintaining a custom version of Cordova with changes to this one little function. Doing this causes overhead in development as you'll need to spend time updating and retrofitting code into new versions of Cordova (along with maintaining builds for your version of Cordova). This brings us to option three: Cordova plugins. Plugins can be written by developers to extend or add (or in our case enhance) functionality and features to their app. Plugins are bits of web and native code that allow developers to work a bit closer to the native layer without leaving the comfort of having a hybrid web app.
So, we now know the problem, we have some initial information on the Cordova source code, and we have some potential solutions.
What now? Our chosen solution was to write a Cordova plugin that works to override Cordova's implementation of
the
OnReceivedSslError
method and allows you as a developer to handle certificates in a more secure and flexible fashion. At this point,
I assume you have a basic understanding of Cordova plugins so I won't be digging too far into our full implementation
- I'll just be going over the core pieces that make this work. To start, you'll need to create a Java class that
extends from either
IceCreamCordovaWebClient
or
CordovaWebClient
. This class houses the function we'll be overriding. From here, you're all set to override
onReceivedSslError
any way that you see fit. As an example, here's one simple way to override it that allows your users to accept
or deny invalid/untrusted certificates.
From here, you'll need to create, and set as default, your own custom
CordovaWebViewClient
in the Java activity file. This allows us to bring in our own custom implementation of
OnReceivedSslError
without much hassle. The code is very simple and an example can be found below.
Once this is done, you're ready to give things a spin. Now when attempting to connect to an entity with an SSUIC, a prompt should appear with the ability to continue or halt the connection.
While not a perfect solution, this does allow users to decide for themselves if they'd like to accept or reject invalid/untrusted certificates. With a little more work, you can provide more insightful information, such has the error received and certificate details. This will allow users to make a more informed decision when establishing connections. You can also investigate whether or not it's valuable to store your users' choices across app sessions by leveraging local storage. Later down the road, we'd like to investigate getting such a solution integrated with the Cordova code base or at least be able to work with the Cordova folks to offer an official plugin of sorts. I hope you have found the information in this post to be of value and I hope it allows you to better serve and protect your users.
Matthew Alcorn is an iOS/Android Engineer for IBM Flex System Manager.