Common coding fails when writing Android mobile apps
@TheKenMunroShow and I gave a short talk at the Infosecurity Europe show recently about some of the most common security flaws we find in Android apps.
It’s amazing how many simple issues create significant security holes.
Here are a few of them, together with a legitimate reason for waving a big pink Android-app-driven internet-enabled vibrator around in a security talk.
First, a reminder of how easy it is to decompile
Android apps are written in Java, converted to Dalvik bytecode then packaged in to an APK. This is trivial to reverse, using something like dex2jar.
This converts the Dalvik executable files (DEX files) and bytecode to Java bytecode and class files, which can then be loaded into a disassembler, or decompiled through a decompiler such as JD. As Java statements tend to easily map to predictable bytecode, it is easy to decompile them by looking for these known patterns and trying to match them back.
There are two simple ways to counter this:
- Use a code obfuscator, such as the official Proguard plugin, which will mangle variable and method names to make them harder to understand
- Write your code in an open fashion and assume that the source code can be read
Obviously option 2 is the preferred choice, as this generally means that architecture and security is introduced to the development process from the start.
The difficult bit should be repacking your modified code and deploying to the device. Except it isn’t; whilst Android app code has to be signed, it can be signed with any key.
There’s more to it if it’s submitted to the Play store – Google load the app into a simulator to see whether it does some dodgy stuff.
Hard coded creds
It’s never a good idea to include static creds client side, but particularly bad when the code can be so easily reversed.
Don’t do it!
Even in 2015, we frequently find mobile apps that don’t encrypt the traffic between the mobile app and the services they consume.
Yes, SSL & TLS have their challenges, but that’s no excuse not to implement them.
Here’s some of the code from My Friend Cayla, our swearing interactive kids doll . Man-in-the-middle the kids’ internet connection and you can listen and send a lot to the doll, as there’s no SSL in place.
The Android permission system has a set of granular defined permissions that can be requested by an app, only at install time. This is generally a poor practice as it only gives the user one chance to choose whether to use the app or not.
Requesting too many permissions could have many effects such as:
- Reducing the audience for your app as users get scared of excessive permissions
- Getting negative feedback for your app
- Training the users to blindly accept excessive permission on all apps
- Making it easier for malware to mirror your app, as the user already accepts that the app has excessive permissions
- Users tend to blindly accept updates, including increased permissions (“permission creep”)
Ensure that you only request the permissions you actually need and ensure that there is a full business justification for each one. Ensure that this justification doesn’t include the phrase “because it’s easier”. Laziness generally does not improve security.
Some permissions, such as ACCESS_NETWORK_STATE, allow the app to discover things about the user’s device (such as the wireless SSID) that could be identifying, so ensure that all data retrieved is appropriately secured.
If Android 4.2 and 4.3 is supported, it should be noted that there was a hidden widget, called App Ops, which allowed the user to override permissions on objects and Android M will allow more granular permissions that can be overridden by the users. To fully futureproof the application, all API calls that require permissions should be checked for errors to ensure that they have succeeded and handled gracefully by the app.
Here are the permissions for WeMo, the home automation system from Belkin. That’s a LOT of permissions and it’s hard to see how all are justified:
Android was designed to allow SD cards as cheap extra storage. Internally this is called “external storage” and is present on most Android devices. If there is no physical SD card slot, it is often emulated. By default media files are stored on external storage. This is the file system that is visible if the device is connected to a computer.
Each app is assigned a working area on external storage that they can use with no extra permissions.
This is typically an SD card or an emulated version of one. It uses FAT32, which doesn’t come with file permissions. This means that app apps on devices prior to 4.4 can read most data stored on external storage outside of an apps working area. After 4.4, the permissions, READ_EXTERNAL_STORAGE is required to read this.
Avoid the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions unless there is a full business justification – they are usually not required for most app’s purposes.
Rolling custom credential storage
Android has had a keystore since version 3.0, but most apps don’t use it, preferring to “roll their own”. These can often be found in the application’s sandbox either in text files or in a SQLite database. Even Android’s native email app does the same:
And Android stores your wireless keys in plaintext too…
So do bear this in mind when you consider that side channel attacks, such as abusing bootloaders, use of hardware ports or malicious firmware, can be used to gain access to the application’s sandboxes.