Securing a PhoneGap/Cordova Hybrid Mobile App

Unbeknownst to many PhoneGap/Cordova developers, the HTML/JavaScript/CSS assets that make up your mobile app are not compiled or otherwise obfuscated when the final app package is built. Unlike the true native bits of the app (i.e. the Cordova framework and custom plugins), which do get compiled into byte code, the core HTML5 assets exist, as they are delivered, inside the app package.

Did I scare you? Hopefully not, as there are numerous ways to better secure your hybrid mobile app, keep your secrets secret, and hide your intellectual property from prying eyes. Let’s get started!

Keep Your Secrets Out of the Code

Maybe this is common sense, but it’s an important point: If something doesn’t need to be in your app’s codebase and you don’t want people to find it, then don’t put it in the code. Treat your hybrid app just like it’s a mobile web site. Assume the worst. Assume people are going to crack open the app and examine the contents, just like they can right-click to view source today.

Strategies to keep sensitive bits out of our code

Any sensitive business logic should be executed on the server. This is rule number one. Run your logic on the server, and expose the results via an API. This could be an API you write yourself using, for example, an ASP.NET Web API project – or you can let Telerik do the heavy lifting for you by taking advantage of Telerik Backend Services. Backend Services allows you to create a secure backend for your app that lives in the cloud and includes two features called “Cloud Code for Data” and “Cloud Functions”:

telerik backend services cloud code

Cloud Code for Data is best described as a trigger in a traditional relational database. You create functions in JavaScript that live in the cloud and are executed whenever a data record is created, read, updated or deleted. For example, you could use cloud code for validating a request like so:

Everlive.Events.beforeCreate(function (request, context, done) {
    var email =;
    var isValid = email && Everlive.Validation.validateEmail(email);
    //check whether the email is not null and whether it is valid
    if (!isValid) {
        Everlive.Response.setErrorResult('The "Email" field must be a valid email address.', 131, 500);

But the options with Cloud Code for Data are really endless.

Cloud Functions are JavaScript functions, also hosted in the cloud, that are executed only when you call them. Once you write a Cloud Function, it’s available via a URL and can even accept parameters and return values.

Secure Your JavaScript

someone talked

If sensitive code just has to be in your app, make sure you are securing your JavaScript as best you can. By its nature, JavaScript is not compiled – so the best we can do is obfuscate it to the point where it is as unreadable as possible. Before you submit your app to the app stores, minify your JavaScript assets with Uglify. Or even take it to the next level with a paid service like JScrambler, which goes beyond obfuscation and provides more active protection of your JavaScript assets.

Note that in Telerik AppBuilder, you can specify that certain files themselves exist only in debug or release configurations. So if you are testing an app, use un-minified/obfuscated resources with the *.debug.* syntax, as in myapp.debug.js. Likewise, you can include more secure (minified/obfuscated) resources with the *.release.* syntax, like myapp.release.js for when you publish to the app stores.

Not only can you manage your debug/release files in the AppBuilder IDEs, you can also automate the process using the AppBuilder CLI and Grunt. TJ VanToll has a great example on using these tools to automate minification (with Uglify) and builds (with AppBuilder).

Load JavaScript Remotely

Another viable strategy is to not even include your JavaScript assets in your app, but rather load them remotely when the app starts up:

<script src=""></script>

However, this isn’t very secure as a quick scan of your source code will reveal the true source. A better implementation would be to load your remote JavaScript via a secure API that first authenticates your user:

    type: "POST",
    url: "", // authenticate your user
    data: { username: username, password: password }, // use the authentication parameters that are best for you
    success: function (e) {
        // check for a successful authentication, and if so, load the script reference returned from your api

You could supplement this on the server side by also making sure that only mobile browsers are trying to access this API. While it’s VERY easy for someone to spoof a user agent, it can’t hurt to add an additional check on the server. For example, in an ASP.NET Web API, you could use the following two lines of code to make sure only iOS/Android/WP8 web views are accessing your API:

var userAgent = Request.Headers.UserAgent.ToString();
if (!userAgent.Contains("Mobile Safari") && !userAgent.Contains("IEMobile")) return;

Keep in mind that this is hardly future-proof either, as the new version of IE (a.k.a. Spartan) names every browser except itself in the user agent string!

When necessary, secure all of your API calls! Ideally, your app would request a key from your server once a user has authenticated themselves successfully. This key could then be passed back to every API call you make, validated on the server, and handled appropriately. The scope of what is required to handle this is not difficult, but due to time and space restrictions, I’ll have you look at this post that outlines the process very well.

Transmit Data Securely


It’s not just about securing your JavaScript to protect your IP, it’s also about securely transmitting data between your app and the server. As a rule of thumb, all outgoing requests should be handled via SSL/https – this is a no-brainer!

However, it doesn’t stop there. In order to prevent possible “man-in-the-middle” attacks, use a Cordova plugin like Secure HTTP to provide true SSL pinning.

Store Data Securely

If you are storing sensitive data in your app, it’s best to do so in the most secure way possible. By default, localStorage sandboxes the data only for your app – it’s not accessible by any other app on the device:

// save some data!
localStorage.setItem('key', 'value');

// get some data!
var myStuff = localStorage.getItem('key');

On iOS, you can take advantage of the security provided with KeyChain by using the KeyChain plugin to encrypt data at rest on your device:

// prepare some variables
var servicename = 'MY_PASSWORDS';
var value = 'LetMeIn!'; // fake of course :D

// prepare the callback functions
function onSuccess (msg) {alert(msg)};
function onError (msg) {alert(msg)};

// store your password in the Keychain
new Keychain().setForKey(onSuccess, onError, key, servicename, value);

// get your password from the Keychain
new Keychain().getForKey(onSuccess, onError, key, servicename);

// remove your password from the Keychain
new Keychain().removeForKey(onSuccess, onError, key, servicename);

Finally, if you are using SQLite as an offline database, you may want to look at a solution such as SQLCipher to encrypt the database. Again, in this scenario, it may be worth considering using a backend data service such as Telerik Backend Services to ensure the security of your data at rest.

Keep Your App Out of the Hands of the Public

telerik appmanager

If you don’t want to risk your app being in the hands of anyone who might try to hack it, then use a service like Telerik AppManager to host your own private app store. This provides you with 100% control over who has the ability to install your app – and gives you the convenience of cross-platform app distribution for iOS, Android, and Windows Phone.

Limit Your Exposure

What else can you do to help secure your hybrid mobile apps? There are numerous other strategies you can use to help limit your exposure to security threats:

  1. Reduce the core Cordova plugins you use. In case of a zero day exploit of a Cordova plugin, it’s best to limit plugin access to only those your app really needs.

  2. Avoid Android 2.3 (Gingerbread) at all costs. Gingerbread is widely considered to be the most insecure version of Android and is no longer supported by Google. The easiest way to avoid Gingerbread is to set your minSdkVersion higher than 10 in your Android Manifest:

    <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="21" />
  3. Use the InAppBrowser for all external web sites. The InAppBrowser Cordova plugin uses the device’s native browser security model and keeps the remote content separate from your app.

  4. Hide app content when switching between apps. Use the PrivacyScreen plugin to help your users hide app content when switching between apps on iOS or Android.

  5. Use iOS Touch ID. If you’re developing for iOS 8, you can provide users with a secure authentication mechanism by using the Touch ID cordova plugin.

Full App Encryption


Last, but definitely not least, is the nuclear option. It is technically possible to modify Cordova to encrypt all of your HTML/CSS/JS assets as they are stored on the device, and then decrypt them at runtime. An oft-referenced tutorial to do so on iOS may be found here, but your mileage may vary.


When it comes to security, nothing is 100%. The goal is to get as close to that number as possible though. Start by limiting your exposure and putting as much sensitive data and logic on your (secured) server as possible. From there, work through the list provided and make sure you are doing your best to secure your hybrid mobile apps.

Portions of the header image courtesy of David Goehring


  • disqus_0erBURKGtZ

    All client side code is vulnerable (no matter what you do), even in native apps (see decompilers). End of story.

  • I think a few things could stand to be clarified here:

    1. `localStorage` can be used for data storage, of course, but it should never be used for secure storage. Although sandboxed, the files are easily obtainable by anyone with access to the device, and the sqlite backing store is human-readable. Any secrets stored in `localStorage` will be there for anyone who knows to look there to see.
    2. Uglification, obfuscation, and even encryption of the JS code does little good (for security). Any obfuscation can be easily undone. Trivial to discover and undo. In other words, put nothing in your client-side code (JS or native) that the world can’t know about. TBH, I don’t think encryption here is the way to go, either. A lot of complexity for very little payoff, in my opinion.

    3. One needs to be worried about network connectivity and server reachability when loading scripts remotely or talking to an API. Unfortunately *how* one deals with this is highly app-specific, so there’s no one-size-fits-all.
    4. A jailbroken or rooted device complicates your security quite a bit, since there’s no guarantee of even the original protections the device’s OS provided.

    In addition to the items in this post, it’d be wise to consider:

    1. DOM Injection: avoid `innerHTML` and the like. Use `textContent` instead. Even with HTML5, `innerHTML` makes it easy for user input to compromise the DOM of your application and do nasty things.
    2. Using CSP (Content Security Policy): this helps you limit where the app accepts information from (for example, you might only want to load scripts from a certain domain). It can also prevent `eval` and other unsafe scripting. Some tweaking here will probably be required, but it’s one more obstacle for a malicious user to overcome.
    3. SQL Injection: When using SQLite locally or when using remote relational databases, always bind. Never construct SQL with user-provided content via concatenation.
    4. Don’t use iframes. If you must, be sure to `sandbox` them.
    5. Filter, encode & validate.
    6. The server shouldn’t trust the client’s state. That is, just because the client says “the user logged in” doesn’t mean the server should take the client at its word. Verify that the user has the proper credentials / a good token. Just because the client says “I have access to x, y, and z” doesn’t mean tat the server should say “sure”; it should verify that the user has those rights before sending any data down the pipe.

    • Thanks Kerry – great comments and even more good advice to be taken to heart.

    • @Kerris great comment. Have a question though. “`localStorage` can be used for data storage, of course, but it should never be used for secure storage.” Is this applies for both iOS and Android platforms? Can you elaborate how the data stored in localstorage can be stolen?

  • Pingback: Links & Reads from 2015 Week 7 | Martin's Weekly Curations()

  • Mario Burdman

    Hi Rob, thanks for the hints, very useful…
    To ensure your app is the only one using the backend, did you considered using this?

  • Perhaps late to the party, my question is other way around, how do you secure your REST API from being accessed by fake apps. Here’s the case – if CORS is disabled or the ACCESS-CONTROL-ALLOW-ORIGIN header is set to ‘*’ at the backend, then anyone can hit the API. This setting is required since Phonegap apps are served at file:// (file protocol). Is there anyway I can restrict the request coming only from a known app.

    • Paweł Skarżyński


  • Andrew

    Hey Rob, A very informative article shared by you… Thanks… i also Found some articles that are good read

  • Pingback: Xamarin vs Ionic for Application Development - Enterprise Mobility, IoT and Business analytics services | Simform, LLC()