Category Archives: Security

PSA: Your Android and iOS Application is not secure...

I was talking to a community member about some of the sites I run (and I mentioned a site called https://AppProtection.net) as they didn't realize I also do a lot of server side work. However, she was shocked that the source code for her app was easily accessible by everyone.

If you write an application with NativeScript, React Native, Cordova/PhoneGap/Ionic (and many other platforms) are you aware you ship the entire JavaScript source code, styles, layout code in your app.

For simplicity we are going to look at a NativeScript application that we will generate quickly so you can easily follow along. These steps apply equally for React Native and the Cordova based eco-systems.

You can uses tools like apkeep to download APK's directly from Google play store, or you can use something like Apple Configurator 2 on Macintosh to download the IPA from the Apple iOS store to your computer. Anything published to either store can be retrieved to your computer directly, and that is when the fun begins...

How easy is it?

 ns create demo --js
 cd demo

This command creates a demo application, for simplicity I'm just going to use pure JS, but again this applies to all the NativeScript flavors, Vue, Angular, TypeScript, React, etc.

Now we are going to make some minor changes to the main-page.js file to look like this, as we want emphasize that any secrets are NOT secret! This includes all Tokens, your http(s) URL endpoints, API keys, passwords, usernames, etc....

import { createViewModel } from './main-view-model';

const secret_HTTP_APIKey = "Hi_IM_A_SECRET_TOKEN_USED_ACCESS_SOME_API";
const private_Firebase_Token = "Hi_IM_your_Secret_Firebase_token";

export function onNavigatingTo(args) {
  const page = args.object
  doSomethingWith(secret_HTTP_APIKey);
  doSomethingWith(private_Firebase_Token);

  page.bindingContext = createViewModel()
}

function doSomethingWith(value) {
  <strong><em>console</em></strong>.log("Pretend HTTP Call with token", value);
}

Now we will build it:

ns build android --copy-to .

I'm using the <strong>--copy-to .</strong> so that we copy the final apk to this folder so we don't have to go looking for it in the platforms/android... folder, you should have something like this now...

The app-debug.apk (or .ipa for ios) is basically what is uploaded to Google Play or the Apple iOS store. Lets look at this file. If you unaware a .apk is just a .zip file with a different file extension. In my case, I just renamed it to .zip so that Midnight Commander (my favorite terminal shell) can navigate inside and view files directly....

Opening up the .zip/.apk file, and for NativeScript navigating to assets/app you will see the files that matter. The bundle.js is your application code, the vendor.js is all the plugins and NativeScript core code, so 99.9% of the time this is a pointless file for reversing your app. However, if you have custom plugins this would have that code. You can also see any worker javascript files if you are using any workers, and angular has some code splitting that can create some other separate javascript files. The bundle is typically the most important file... Lets just copy it out of the zip file so we can open it into a real editor....

How secure is my JavaScript, lets see the main-page.js?

Opening bundle.js up in PHPStorm, this is what we see:

Opening up bundle.js

Interesting it tells us we have 6 files that were compiled into this app.

Lets look for the main-page.js inside the bundle! Simply do a search for main-page.js and this what we find around line 100 in the bundle.js file (that is because the prior 80 lines or so is all the CSS that was bundled from app.css and the default imported theme css files)

main-page.js entry

Wow, 100% full source code including all your awesome secret keys and tokens (which I selected)... If you compare this to our file above, the only difference in this code is that we original did <meta http-equiv="content-type" content="text/html; charset=utf-8">export function onNavigatingTo(args) and this removed the <strong>export</strong> from the function on 114 and added it on line 105 - 107 as a __webpack_exports__. Otherwise this code is identical.

What about the layout, Main-Page.xml?

Lets search for main-page.xml, oh it shows up on line 193...

main-page.xml entry

It is just one long string... What happens if we copy & paste it to a newly created test.xml file. How different is this from the original main-page.xml file, not a single change. It is the exact same file.

Uh oh...

Can anyone tell me how quickly I can take your fully released app, that you spent months or years on creating and make my own 100% full clone? Or perhaps even do things more nefarious and add, edit, or steal any data from any of your private endpoints?

What can you do about this?

There is three things that I'm aware of

  • Minification (Built in to NativeScript & React Native)
  • Obsfucation (Lots of different tools)
  • Encryption

Minification

Well, the first thing people think of the minimization using Terser (or uglify). NativeScript uses Terser by default.

Lets see what happens when we minimize the code using NativeScript 8. Here is the bundle.js file using minification.

Minimized output

This looks hard to parse... But lets see what happens if we use the awesome "Reformat code" option in phpStorm/webStorm...

Code automatically reformatted.

Well, it is different, but still totally readable. How about the main-page.js and our secret keys?

Well that id disappointing, the code is perfectly readable and usable. All your secrets api keys are well, not at all secret. The only thing missing is all the comments were stripped and my "console.log" was removed from the doSomethingWith routine. But the code is very readable and can be dropped virtually as-is in a new main-file.js javascript file. If I wanted to make this file to work in a new app, I would just need to replace "r" with "require" and add the "export" to the onNavigatingTo function and it would be 100% working. Add a couple refactors like "t" to "page" and extract the API keys to variables and it would be virtually identically to the original you wrote. Lets see, hacker 5 minutes, you 5 months.

As you can see minification does nothing really to hinder anyone. But it is a good step for optimization but adds zero security.

Obfuscation

What about obfuscation, this really depends on the tool. I have a blog post about this security of this. However, rather than re-iterate it, it is almost as trivial to reverse as we just did with minification. The only tool that took me longer than a few minutes to reverse was JSScrambler. However for JSScrambler to work you have to set this at its highest level and enable code protections so that a hacker can't easily modify the code. Unfortunately, the last time I tried this is slowed all of the code down by 30-50% the entire life time of the application.

Compiled Code

This is probably the next best thing, if you create a function that has your api keys encrypted in it and you have to call a couple functions to return them before you use them they won't be visible in the source which seems like an awesome win. However, if your JavaScript code has:

const api = getAPI(); 
const key = getKey; 
https.get(api+key);

Do you have any idea how quickly I'll get your api & key, I'll just change the code to be:

const api = getAPI();  
const key = getKey;  
console.log(api+key);

Did you slow me down, yes, by how much -- maybe 15 seconds to modify the apk and upload it to by emulator (or a jail broken android/ios device) . So if you use this method, please do NOT telegraph how to get your Key & api endpoints. At least be more discrete as when I do a search for "https" or "firebase" in your code base you don't want to point me to where I need to go next.

React Native offers a engine called Hermes where it partially compiles the code, this is more secure than the pure JS code mode, but obviously not as secure as pure compiled. However, even in pure compiled code, if you do nothing to obfuscate your keys and api end points, just running strings against it will give you everything a hacker needs to attack your end points.

Encrypted Code

First a major disclaimer here -- I am the author of the AppProtection system, of course I recommend it. Second disclaimer, this is currently NativeScript only, but if I get enough interest for a React Native version, I'll port it as I have all the code all done for both v8 and JavaScriptCore engines. But I have to spend the time adding it to the React Native tooling. Basically this encrypts the source code for your release apps. This is what a release file looks like:

Encrypted Code

The source code AES encrypted, and the only unencrypted copy is in memory (never saved to disk) while the app is running. The actual v8/JSC runtime engine itself has the modifications for understanding AES encrypted JS code, no extra code is shipped in your app. Is it perfect? Nope, but it adds another very difficult wall to climb...

The 100% Solution

Click bait! Sorry there is no 100% solutions. I haven't heard of any of the AppProtection applications being cracked, but that doesn't mean it can't be (or hasn't been). I will tell you upfront everything can be cracked, including AppProtection. Even Denovo which is used in high profile games and has millions of dollars in revenue. Eventually, each new release gets cracked. Everything can be hacked with enough time, patience and knowledge. However, the whole idea of security is you put enough walls in front of your attacker to make him want to go to a much easier target. If they leave, then you have thwarted an attack. Do you really think most attackers or application cloners want to spend weeks pulling your data or cloning your app, or switch to something that only takes them a few minutes?

More information

  • I have another blog post I wrote in 2019, everything is still valid and I discuss other things you can do in your app for security and other security gotcha's.
  • I am available to do consulting work to help you beef up your security both server and mobile. I also do core reviews, and training if your developers need to learn some better practices.
  • You can email me at nathan@master.technology

Mobile Application Security

Security is never perfect, the minute the device is under the control of an attacker; you have issues. So the primary goal of security is to raise the bar so high; that it becomes much more profitable to attack your competitors app then your app. Don't make your app the easy target.

So, recently I have seen several blog posts and even a podcast in the NativeScript community on Mobile application security. Unfortunately; some of the advise is just wrong. I really hate to be harsh; but giving out bad advise is far worse in my opinion, than giving no advise when it comes to security of your application and infrastructure.

Lets talk about the Good, Bad and the Ugly... Lets start with the Bad.

Bad Advice

Would you really accept someone saying it is super secure to set a cookie to "isAdmin=1" for allowing admin access. Well, I'm here to debunk several things that I've seen show up recently as they "sound" good, but are still bad advice in most cases.

First, in a couple blog posts I read, and the pod cast I recently listened too, all recommend using NativeScript-Secure-Storage for storing secure local data. Simply put you are just as safe using my NativeScript-LocalStorage plugin (which has no security at all) as the Native-Secure-Storage plugin in all cases that I can think of except one very specific case 1. (So basically; you have added no extra security to your app in almost all cases to just using raw file storage on the platform.)

How is that you ask? Its encrypted storage using industry strength encryption systems. Well, the issue is that any person attempting to pry the secrets out of your app; will be running it on a rooted phone (iOS or Android, doesn't matter the OS). With a rooted phone, I now have full access to EVERYTHING on the device including the secure "storage" files. Bam, game over; do not pass go! I now have your secrets that you thought you "securely" stored. As you can see a pretty pointless plugin in all reality for securely storing anything. ( This is a bit of a simplification, but for someone who knows exactly what they are doing -- they can trivially pull all the values out of the secure storage plugin in literally only a couple minutes on any rooted device. )

(1) - Using JSScrambler or AppProtection can mitigate most of this issue, there are still some corner cases that might still allow access to all the data even using these products.

API Endpoints and Keys

The next thing I heard talked about was HTTP, Kinvey and API keys; the advise wasn't bad so much as incomplete. This isn't specifically against NativeScript 4, (or Kinvey), because really React Native, Titanic 2, Phonegap/ionic/Cordova 3 , and several others are all JS code based; the JS code is shipped with the application; meaning the code can be fully read by your attacker. So when you have in your plain JS code:

Kinvey.init({
   appKey: '&lt;appKey&gt;',
   appSecret: '&lt;appSecret&gt;',
   encryptionKey: '&lt;encryptionKey&gt;'
});

or

const result = http.get("https://master.technology/secretApiPath?appKey")

Guess what I now have access to? I have access to the ability to read (& write?) any data your appKey has permissions to do. So it is very critical to initially assume this code is 100% readable and that none of this is secured at this point. So make sure you plan the usage rights for all your keys and api endpoints properly. If you don't plan for this, then your appKey may give me access to read and write things that even the app doesn't do, which could be really bad for your overall security footprint.

Again, I want to stress this is NOT specifically talking about NativeScript; as this same advise applies to React Native, Cordova, Titanium, Flutter, Java, ObjC, and pretty much every environment. If I can get the API keys out, I then have the full access that your key offers. Now JavaScript based systems are tremendously easier to pull this out than say; something using compiled code (like Flutter or ObjC). However, you know what I would start with on a 100% native app? I will just run strings on it... Its amazing what is easily seen in plain text from a compiled applications like all your endpoints and keys.

(2) - Titanium has a built in encryption of the source code. However, last time I looked it was the same key for all apps; once you have the key (which of course I do ☺) -- it is trivial to decrypt all the code in every single Titanium app. But I will admit it did take a bit of time to figure out the key, so it isn't bad system.
(3) - Cordova has a third party plugin to encrypt the code; I spent less time breaking it than I did downloading it. To say the least it was the simplest of the bunch.
(4) - NativeScript HAD an official plugin, after pointing out how easily I could break it; it was dropped shortly after. I believe you can still find the repo for it -- and you can probably still use it; but it really is as trivial to break as the Cordova plugin.

Encryption

So in this case; any api keys and important endpoint urls; are better off encrypted in the app. That won't stop everybody; but it will make the bar to get the values out a lot harder. This applies to ALL app types! You want to encrypt or obfuscate the data and do not make it trivial for them to find it. If your JS code says:

let apiKey = "##DS#F#1%F#aD#D#";
apiKey = decrypt(apiKey);

Guess what code I'm going to look at next? So using the decrypt right next to the assignment is not going to slow me down in the slightest. Now using it somewhere in the middle of something completely unrelated might actually make me miss it, especially if it is not called decrypt but something like initializeCameraModule. So if the value you stored in your apiKey is not a real apikey but a obfuscated key and since I am unaware of it, you cause me a lot of wasted time as I'm trying to figure out why my external calls to your api aren't actually working properly. Again, wasting my time is the quickest way to make me want to attack a simpler or softer target. Now someone paid to figure this out; will figure it out; but a casual hacker might give up. Each barrier that you can raise and actually waste a bit of time 5, will discourage and drive up the costs to figure it out.

Another partially bad advise is the use of Encryption to keep your data at rest in a state that it is not easily retrieved. It sounds great! But this suffers from the exact same issues as discussed above. If I have easy access to your source; I'm going to trivially find your key and then decrypt all the data. This exact same warning also applies to my own encrypted SQLite product; if you don't protect the keys; I can pull all the data out.

So doing something to hide the keys is critical.

One potential solution if your app has a login, is that when the user types in the password for login it is used to calculate a new encryption password, which is then used to access the encrypted data store or sqlite database. Then, since I, the attacker don't know the password, I have no ability to ever retrieve the data from any data at rest no matter what I do unless I convince you to give me your password.

(5) - Any place you can seriously waste the person attacking your app's time is pure gold. Eventually they will figure it out; but in the meantime you drive up their costs and frustration. At some point, if those costs are significant enough, they will stop and attack an easier target. Their are many other techniques that you can do while working with keys/endpoints that can waste significant amounts of time and should be considered.

Compiled Code

In some cases it might be in your best interest to have compiled C code that sets up certain values and/or decrypts parts of your data. This makes it a lot harder to figure out what is going on, and can store keys you want protected. However, if your source code is still plain text, then I can easily see how/when you are calling it, add breakpoints and then determine how it works. So this really again can add no real security or can be an extra high barrier depending on what other protections you have in place.

Source Code

There are two things about the source code in JS based apps that you need to consider.

  • The first is that any secret apis, keys, endpoints and your proprietary business logic are easily found.
  • The second, which is related but a different aspect which might concern you more; is that I now have all your source code. I can easily create a clone of your cool app on the app stores with literally no development costs (new startup screen, some css color changes) and then totally undercut your price.

So lets look at some ways to try and mitigate the primary issue of visible source code...

The Ugly

A lot of people believe Obfuscation is a good and a valid answer. Since it is frequently put forward and considered a valid solution; and so it is recommended; this is why I consider this the Ugly.

Obfuscation

Now one thing that they got correct in the blogs & podcasts; was that obfuscation actually does very little. In fact other than JSScramber, the rest of them that I've played with are literally only one step above useless. If they minify your code; they have some usefulness as your app size goes down. If they slow your app down, then they are actually worse than worthless. But odds are very likely they will not have any performance hit. Unfortunately, almost every single one of them, by dropping the code into a decent beautifier, will eliminate almost all obfuscation. So using obfuscation (which includes the recommended NativeScript --uglify flag you see in some posts) really presents absolutely no additional security beyond the minification of making myFavoriteVariable become c. That can eliminate some really basic understanding. But an average JS developer can easily still read the source code. If I'm the one breaking your code; all I'm going to do is just drop the newly beautified code in phpStorm and refactor any variables as I figure them out and then we will be right back at pretty close to your original code rather quickly.

It can slow the attacker down some, but really it is something that won't really cost that much time as refactoring and code insights will allow me to trace things down rather quickly. So in my opinion; this really offers very little value. In addition most Obfuscation will NOT change any of your static strings. So if you had:

let apiKey = "xyz"; <br>http.get("someurl" + apiKey)<br>


and it transforms it to:

let a="xyz";http.get("someurl"+a);<br>

Does that really stop anyone from understanding that a is probably the apikey?

In addition, just a fyi -- in all cases (except JSScrambler) of obfuscation that I have seen and played with I have broken the obfuscation is less than 30 minutes, most the time in a couple minutes just using a beautification will do it. But there were a couple that actually required a few minutes to read through the output to figure out where to attack it at.

The Good

Lets discuss the best ways to potentially handle the the security of your application, lets look at the two possible ways to handle this..

JSScrambler

JSScrambler actually provides really good Obfuscation at the higher levels. But for the highest quality obfuscation your app pays a significant speed penalty constantly; like up to 50% slower depending on what the code is doing. So this is one of those things you have to evaluate if the added security is worth the performance hit and choose the security level you are most comfortable with. On some of the lower settings, there is no constant performance hit; but it is a lot more trivial to eliminate the obfuscation. This is one area you can increase the bar extremely high. Which would potentially not make it worth the time to attempt to figure out your app, but their is a serious price to pay. Now I haven't heard of anyone that has actually hacked JSScramber set at the highest level; but do you really think anyone would tell you if they could? Please feel free to pay me to find out how secure it is.

Encrypted Source Code

There is one other service AppProtection.net that offers encrypting the source code. This actually is my product/service; so major disclaimer here!!! I think this also raises the bar extremely high . With AppProtection; I encrypt all app JS code and the V8/JSCore engines decrypt the files while running. All my tests had ~10% slow down during the loading of encrypted code as the code had to be decrypted in memory. (No decrypted code is save to disk at any point, it is always only in memory), so each time you start the app you have a perf hit. But you do not have the "constant" hit as with higher levels of JSScrambler, since the code is running from memory will already decrypted. However, as with anything; someone extremely skilled in debugging can eventually even break this also.

So in all reality the only real solutions at this moment to actually protecting your source with NativeScript is JSScrambler or AppProtection. With other products like React Native or Cordova, JSScrambler is the only current solution. (Please note; if I get enough requests for React Native, I could bring the AppProtection tooling to it as the code already runs on JavaScriptCore)

So now that we talked about the Good (Source Encryption), the Bad (false information that doesn't help) and the Ugly (Obfuscation). So, lets discuss a couple related items..

SSL Pinning

Using SSL Pinning can be very valuable for the opposite side of this; making sure your app is actually talking to your server. This will eliminate Man-in-the-Middle data watching. So if you are transferring data that you value; you might consider adding SSL pinning to your app. However you do have to make sure that you plan for how you will update the key with the new SSL key when it expires.

Security in General

I am going to re-iterate; their is NO PERFECT security, all security can be eventually broken. It is impossible, once the app is in the attackers hands to stop them. Just look at how frequently Denuvo gets cracked -- they are paid millions to get it correct and are constantly updating the security and it still gets broken frequently. So once an attacker has your app, they now have the ability to do anything I want with it. So the goal is to what we call security in depth. Do multiple things that raise the bar as high as you are willing to pay the price. As their can be a cost for each security measure you implement. For example if you are super paranoid; you could use AppProtection, JSScrambler, and multiple native C modules all in the same app. Then if the attacker finally broke one aspect of your security their are still several others blocking them from going forward. Now that is being ultra paranoid, but their is nothing stopping you from doing it.

Final Notes

If you are working on an app that needs to be secured and/or you want someone to do some security contract work on your app and/or the API endpoint infrastructure, we can assist in this. If you would like someone to attempt to break your app's code and suggest additional things to strengthen your apps security footprint; again please contact us at master.technology

About the Author

I am the owner of Master Technology, which focuses primarily on server side work and desktop apps. If you need any NativeScript work done; from optimization, code reviews, training, help on an app, creating plugins, and even full apps created. Please feel free to inquire at master.technology.

Introducing NativeScript-Protect

(c) 2014, Yuri Samoilov

(c) 2014, Yuri Samoilov

UPDATE: Works on iOS and Android; see https://AppProtection.net.

Have you spent months working on the perfect application?  Are you now worried someone will just copy your source code right from your NativeScript application?  (This is not a unique issue to NativeScript; ReactNative, Titanium*,Cordova/PhoneGap and any other platforms that are not compiling Java code have this exact same issue. )

Well, I have a solution for you.  After a lot of hard work; I am proud to introduce my first commercial component into the NativeScript eco-system;  NativeScript-Protect.   The NativeScript-Protect plugin is a (very) simple  install and then it will automatically encrypt and/or minimize your source code while you are building your release version of the project.

It automatically ties itself into the NativeScript (tns) command so that you do not have to do anything. When you run anything that does a build; it will automatically encrypt and/or minimize your build copies of the code.

This does NOT touch your original source code; only the BUILD copies that the NativeScript (tns) command copies into the build system.  So it makes itself a seamless part of your standard build process that you can just totally forget it even exists.

The initial release is only for Android; but I expect to have the iOS runtimes done early next year.

If you would like to see it in action; I have a 4 minute video showing it from start to end.

In addition, two demo APK's compiled as a debug app with everything encrypted or just the main app files encrypted, can be downloaded for you to check out and kick the tires.
If you have any questions; please feel free to comment here, or contact me via the contact button on the nativescript.tools website.
* - Titanium has a encryption step; however it is rather simple to decrypt system and so in my book this is actually worse than no encryption since it gives a very false sense of security.
UPDATE: The current version turned into AppProtection.net -- So it fully supports Android & iOS.

Adding External Resource Security

lock-143616_1280In a lot of larger web sites it is pretty common that you use several third party resources like JavaScript.   However, this is a potential malicious door into your customers computer via your website.   What happens if the third party resource is changed by someone who does not have your best interests at heart.  Your page will still happily load the malware right onto your customers browsers.    So what can you do about this?

Well I'm glad you asked.   In the just released Chrome 45 (and soon in an upcoming Firefox release), they have added a awesome new feature to protect your customers (and your reputation).   When you link to any resources in your web page; you can now use the integrity attribute to tell the browser that this file must match this hash to load and use this file.

So <script ... integrity="sha256-some_sha256_hash"> or <link... integrity="sha384-some_sha384_hash">

The browser integrity attribute must support the sha 256, 384 and 512 hashes according to the w3 spec. For browsers that don't support this yet; then this won't do anything and the resources will load fine just like normal.  But in browsers that do support this; when the browser downloads the resource it will hash it and verify the hash matches before allowing it to be used.

On Linux you can generate the hash by doing:
cat the_file_resource | openssl dgst -sha256 -binary | openssl enc -base64 -A

On Windows if you have openssl installed you can do:
type the_file_resource | openssl dgst -sha256 -binary | openssl enc -base64 -A

Or if you don't have openssl installed; you can also easily cheat by using Chrome.   Just add the integrity with a bogus value; then reload the page.   Chrome in the developer log will show you the computed hash for the file when it blocks it.

For the full W3 Spec: https://w3c.github.io/webappsec/specs/subresourceintegrity/