![](https://cdn-images-1.medium.com/max/800/1*qbRZhtLBJwV7jWI7WgkorQ.png)
Securing your Android apps #SecurityMatters
App developers tend to be quite reactive when it comes to app security. Sure there are apps out there that require security to be a focal point, but in reality, for most apps, security isn't big concern till something goes wrong. Here are a few tips I've found that you should keep in mind to help you pro-actively build secure apps.
Its nearly impossible for me to cover every scenario for you, most apps will have fairly distinctive security requirements, however we can follow the 80–20 rule and cover the most common app security aspects. That being said, I strongly recommend you read Android Security Tips.
App security falls largely into 3 categories:
- Networking
- On device storage
- Good coding practices
Networking
There are a few different ways in which a malicious hacker can get a hold of your data by exploiting network traffic, the most common ones are:
- Trick your device into proxying through one of their servers to connect to your end-point. Not unlike the debugging proxies you may use while coding. The difference here is that he will emulate your end point with a valid certificate and once he has your data (API key, cookie and whatever else) he can connect to your API end-point and get more data. This sort of attack is easier than you think, you would simply have to set up “free WiFi” and configure the WiFi with a DNS server which resolves all domain names (or the domain names the hacker is interested in) to a malicious server. When you connect to the WiFi and try to access your site… boom, you’re compromised. This alone is a great reason to never trust free WiFi or do anything sensitive on public WiFi. There are a few different variants of this attack but the general concept is the same. This kind of attack is known as a Man-In-The-Middle (MITM) attack.
I realize that SSL certificates will likely throw up errors in this scenario and the hacker will have to use a self signed certificates or certificates issues by a valid authority that don’t match the domain, however there are still scenarios (that I'm purposefully glancing over) in which your app can be compromised. - If your network traffic is not secured, a malicious hacker could simply sniff the network for traffic, he would really only have to listen for activity on certain ports such as 80, 443 or 8080 and he would pick up most unencrypted web traffic.
- User can input malicious data in order to break your code.
How to protect your app
The absolute basics here are:
- Always use SSL connections if there is anything sensitive at all about your apps data.
- Never use self signed certificates in production. As a matter of fact, avoid them in testing as well.
- Disable HTTP redirects in your networking library/code. Some libraries disable this by default. Having these enabled can make MITM attacks a lot easier.
- If the user is inputting data, always escape it using URLEncoder.encode(userInput, “UTF-8”); if the data will be used as part of a URL.
Side note: Its mentioned later, but always escape it, if its going to be used for DB queries as well as if you’re saving the input to a JSON or XML file. - Set a maximum length on every field that requires user input.
- Validate the input.
Pro Tip for Networking
If you want to use self signed certificates securely and/or want protection against MITM attacks, you should be using a technique known as Certificate and public key pinning or some times referred to as Certificate pinning.
Normally certificates are validated by checking a signature hierarchy store on our device. MyCert is signed by IntermediateCert which is signed by RootCert, and RootCert is listed in your devices “certificates to trust” store.
Note: The problem that often comes up on Android is that the “certificates to trust” does not contain some well known certificate issuing authorities. This technique can help you bypass that problem as well.
In certificate pinning, you ignore the standard procedure of checking the signature hierarchy and tell your app to only trust a certain certificate. This means that if someone does a Man-In-The-Middle attack, your application will reject his certificate even if it is issues by the president of VeriSign himself.
Here are a few good resource on implementing this in Android.
- Implementing a X509TrustManager is the best way to go. The Open Web Application Security Project has an implementation of certificate pinning on Android.
- This blog has an older way of implementing certificate pinning, personally, I like the idea of bundling the certificate as a raw resource. A combination of the two approaches may be best.
- If you’re not into doing the hard work yourself, there is an AndroidPinning library. Please have a look at the bugs raised on the library first and make sure nothing affects you if you go down this route.
On device storage
This area is covered well by Android Security Tips. The truth is, the most secure way to store data on a device, is to not save data on the device to start with. Unless you have a security team auditing your app looking for all possible loopholes, if possible, avoid storing truly sensitive data on the device. That being said, since I know you’re a renegade, there two main scenarios here:
- Internal data storage.
- External data storage.
Android external data storage
If security is essential, you should not store any data on external storage. The main reason for this is that data on external storage is globally readable and writeable.
If your app happens to be one that needs to store large quantities of encrypted data on the device, then you may not have the option to only use internal storage. Again, this is highly unlikely, because some full-HD games can store almost a gig of data on your phones internal storage. However, if you must use external storage, my advice is:
- Use a binary serialized format (makes it much harder to access the data for the average user).
- Secure sensitive data that does not need to be displayed (such as passwords) as a hash. A hash is one-way, it cannot be un-hashed or decrypted.
- In your data, encrypt all sensitive information. You can secure the information inside your files or secure your entire file using something likeFacebook conceal library.
Android internal data storage
Android internal storage is fairly secure because of Android sand boxing its apps by implementing a UID level control on the files. However, because of issues such as rooting and ADB allowing developers to copy data off devices, internal storage is not as secure as some apps would like.
While a user having root level access on a device is not technically a threat, we should do out best to protect sensitive data.
Internal storage includes but is not limited to:
- Files you choose to persist.
- Temporary files / Cache
- Database
- SharedPreferences
Reading and writing files
The Android Security Tips covers how to deal with interprocess communication and reading writing files to internal storage.
What I would like to add, again, is a recommendation to save your data as a binary serialized format, considering compressing and encrypting the data. Something like Facebook Conceal can provide fast encryption and decryption of files. If you do implement AES, Blowfish or any other form of encryption yourself, generate your passphrase or key using a SecureRandom number generator and save your encryption key in something like KeyStore, if it needs to be reused.
Temporary files and cache
In general, you shouldn't cache or put into temporary storage anything sensitive. Temporary files and cache may include things like network images and HTTP cache. Most libraries should implement a certain amount a security for the HTTP cache and images are generally not a security issue. If either of these need to be secured, you should:
- Clear cache when the app exits.
- Configure a very short cache expiry.
SharedPreferences
This is perhaps the easiest way to persist data for your app. There are someimplementations of secured SharedPreferences on the internet that hash the key and encrypt the value. While this is better than nothing, I would recommend not storing sensitive data in SharedPreferences. If you must, using an implementation such as the one linked earlier and, do not hard code your security key in your code, instead use a SecureRandom number generator to create a random key and save your encryption key in something like KeyStore for reuse.
Database
Database encryption is a bit of a polarizing topic on-line. Generally people fall into one of three categories:
- Don’t put secure data into SQLite
- Only encrypt the sensitive data and, don’t encrypt data you need to query on, or if it’s sensitive, hash it instead of encrypting it.
- Use SQLCipher for everything.
This in general sums up the advice I could possibly have as well, I personally prefer the second approach. However, as mentioned earlier, the best way to secure data, is to not persist it to start with.
SQLCipher I personally have nothing against, however, as a developer, using SQLCipher and simply implementing it alone feels like overkills for most apps. It also bloats the size of your apk as it bundles a version of SQLite into your app.
SQLCipher is also fairly hard to work with with. Querying the database on a device adds a few steps and requires SQLCiphers tools. Overall, I really like SQLCipher as an option, but your data must be super sensitive to justify the development and code complexity overhead.
Good coding practices (Code goodly)
Through the course of this article, I've mentioned various things that technically come under the category of good coding practices. In this section I'm going to list as many of them as I can think off. Feel free to message me and ask me to add more or respond to this article with more best practices.
Validate and Escape user input
This was already covered to some extent.
Always set a maximum input size on all your fields. Validate the input to ensure that it matches your expectation (length, numeric, alpha numeric, etc.).
If user input is being used for URL parameter values, make sure to use URLEncode to escape user input.
If user input is being used for SQL queries, make sure to SQL escape the input if you are building the query yourself. Best way to avoid SQL injection attacks is to not build SQL queries yourself. Instead use the API provided by the framework.
If user input is being written to an XML or JSON file, make sure to escape it.
Pro tip: Apache commons has an StringEscapeUtils class that can escape strings for most common formats.
Do not hard code encryption keys
This is covered above a few times. If you are using AES, Blowfish or an other form of encryption that requires a pass phrase or encryption key, instead of hard coding it into your source, generate it with a SecureRandom number generator and store it in something like KeyStore for reuse.
Secure your Interprocess Communication
I would read Android Security Tips on this one as it cover the topic in good detail. I would however add that with Broadcasts, always useLocalBroadcastManager if you don’t want other apps to intercept your broadcasts. If your broadcast receiver does not need to intercept broadcasts from other apps, register and un-register them with the LocalBroadcastManager. If you want to listen to communication across different apps, then consider adding a permissionLevel=”signature” to your BroadcastReceiver.
Others
- Do not persist sensitive data if you don't have to.
- Make sure your web server sets short TTL or cache expiry time on sensitive data.
- Clear your cache when the application exits (if it contains sensitive data).
- Do not implement your own Cipher.
Finally
In order to build great Android apps, read more of my articles.