Don’t laugh, yes we said store in cleartext. This leaves no protection to your user’s runtime data assuming the hacker has physical access to the phone, which is a big assumption. But as there are so many phones for sale on eBay and Craigslist you have to assume that your app is going to end up sooner or later on a secondhand device. To access all the information in an app’s
/data/data folders use the
adb backup command and then convert it into a
tar format using the Android Backup Extractor or
abe.jar, see Listing 1.
>adb backup com.packagename.android >java jar abe.jar unpack backup.ab >tar xvf backup.tar
Listing 1. Backing up data
Using cleartext means there is no protection to a user’s runtime data – assuming the hacker has physical access to the phone.
A slightly better option used by a significant number of apps is to set the
android:allowBackupflag to false in
AndroidManifest.xmland then put whatever you want in shared preferences or in sqlite databases. The idea being that if nobody can back it up then nobody should be able to access the passwords. Unfortunately there’s a big flaw in this argument. Android is a Unix based system so root will have access to any files on the phone. If the phone isn’t properly wiped when it’s resold the new owner is going to have all the time in the world to root the phone and recover whatever dynamic user information is stored in the
/data/data folders by changing the permissions on the file and then doing an
adb pull instead of the
adb backupcommand. See Listing 2 for a shared preferences file with an exposed password.
<?xml version='1.0' encoding='utf8' standalone='yes' ?> <map> <string name="password">2secret4me</string> <boolean name="remember" value="true" /> <string name="username">androidauthority</string> </map>
Listing 1. Backing up data
A much better idea is to encrypt the password before you store it. If you are going to take this approach then don’t store the key in the APK code or anywhere elsewhere on the phone. It’s never a good idea to use AES, DES or any other symmetric encryption algorithm if you store the key where it can be easily found. It is a relatively simple process to find the APK and then get a copy off the phone. The command
adb shell pm list packages will get a list of the APK’s on your phone. To find where the APK lives on the phone use the command
adb shell pm path com.packagename.android using your APK name and then use the following command to get a copy of the APK
adb pull /data/app/com.packagename.android1/base.apk making the appropriate changes for the package name and path or apk name where appropriate.
jadx base.apk to decompile the code back into java source code to see if you can find the encryption key in the code. If you’re more familiar with
dex2jar then we suggest switching to jadx. It is an order of magnitude better at decompilation than
dex2jar. Lots of apps we audited in the past with
dex2jar have only given up their secrets when we starting using jadx.
Developers are a helpful bunch and they often put the encryption keys in easy to find places like
com.packagename.android.util.security. If that doesn’t work more often than not the code isn’t obfuscated and you can try searching for the class name or phrases like ‘encrypt’ or ‘decrypt’. To decrypt the password cut and paste the decryption code into a java file and give it the password as an argument. Some developers make the encryption key device specific by including device information such as the AndroidID as well as make and model information, but it’s mostly worthless if you can already see how the key is put together in the code. If you are going to use some sort of a recipe to generate the encryption key then obfuscate the code properly so that the ingredients are not super easy to find and if possible store some piece of information or the entire key remotely on a server so not all the information can be found on the phone.
And as your app grows make sure everyone knows how to encrypt and decrypt login information. In one of the dating apps we audited on Valentines day last year we found the password encrypted in the shared preferences and another copy of the password was also stored in cleartext in the app’s sqlite database. Someone either didn’t know the rules or simply forgot to remove old code that stored the password in the database.
If you’re writing a healthcare app and you want to see if it’s HIPAA secure then put your device into airplane mode and if you can still log into the app then it’s probably not compliant with the HIPAA regulations.
The safest option for encrypting passwords is to use asymmetric encryption algorithms such as RSA. Asymmetric means that the key is split into public and private keys where only the private key can decrypt the information. We’re seeing a lot more developers using the Android Keystore to store public and private asymetric key information.
In the Android Keystore this public private key exchange takes place on the device and would seem to be HIPAA compliant. We say ‘seem to be’ as once again if you can root the phone you can gain access to the private keys. Nothing is 100% secure and sooner or later someone will find a way to get at the keys especially if you put everything in the same place. I’ve always had a problem with mechanisms like the Android Keystore as the app developer is relying on the skills of another developer for my security and there is no physical impediment to get at the keys.
Android Keystore public and private keys are stored in the /data/misc/keystore/user_0 directory. The private key is stored in a file that has
<app_id>_USRCERT_<key_alias>. On a rooted phone you can copy the file to another
<app_id_malicious>_USRCERT_<key_alias> and then import it from your malicious app, allowing you to recover the password. Asymmetric Encryption
A safer asymmetric encryption option is to store the private key not on the phone but somewhere else remotely. When the password is first entered, it’s sent back to the server for storage. It’s also encrypted with the public key and stored in the shared preferences. Every time the password needs to be checked the public key encrypted password gets sent to the backend server and decrypted by the private key before it’s checked against the password information in the server’s database. A token is then passed to the Android client to allow access to the app. At no time is the password visible on the phone.
In Android this usually means using the Spongy Castle libraries or other alternative such as Google’s Keyczar. Sure there are other security issues that you have to think about like how to ensure that someone isn’t just sending you a publicly encrypted key from a different device. But it is a lot easier to add extra ingredients to your asymmetric key recipe to foil these type of attacks when the code is on the server. We’ll return to this in the next article.
In the future Lollipop device encryption may put an end to many of these types of attack, but until Lollipop gains critical mass then options 1,2 and 3 are not a secure approach. Our original recommendation is to ask the user to enter their password everytime they login. If that’s not possible then never store the password in cleartext or leave the key in the code or on the device for someone to find. Asymmetric encryption keys using Spongy Castle or Google Keyczar are much better alternatives to consider. In the next article we’ll look at similar options for safeguarding your API keys.