Mobile security and data privacy is a topic emphasised by a number of business owners willing to ensure their customers that their products are safe. Recently, we’ve described the tools and techniques of securing your app in Ruby on Rails. Today, let’s focus on another question:
Is it even possible to make your app 100% safe?
Securing your mobile app — it’s never too much
A lot of developers have no idea how easy is it for hackers to get the data from their applications. To feel secure, they work on the protected devices where each application is sandboxed. Also, as a lot of popular third-party libraries stores the plain text tokens in resource files of their demo apps, many developers copy this behaviour. Finally, the common practice is storing the unencrypted keys or tokens in a seemingly safe data store provided by operating system API or in the local database. Is it all enough to provide the proper security? Unfortunately, not really.
Think like the attacker
Some time ago, we’ve taken part in Mobile Security Lab organized by Niebezpiecznik which is one of the biggest security testing company in Poland. Our knowledge of mobile app security has significantly increased when we put ourselves in the attacker’s shoes. There were both Android and iOS app for which we could bypass the security or get access to some data.We had the opportunity to work with the tools used by hackers and see what they need to do to achieve their goal. Now, let’s focus on the iOS app cracking procedure.
Cracking the app
Official development tools are very useful for regular work, but they can give a lot of information to people hunting for some data inside the app. Otool, for instance, is an application that displays information about the libraries. You can check which architecture they support or if the library is properly signed. It also gives you the information about encryption. Basically, it is not a big deal — the keys are not public so you cannot just decrypt them. But you can easily crack the app when you have access to the jailbroken device.
No, I’m not going to give you the detailed guidance on how to do that. But let’s just briefly run through the process.
Every application needs to load to the memory to be able to run on the device. Before loading, it needs to be decrypted. With access to SSH, GDB debugger and the encryption information from otool, one can easily run the app, attach the debugger and dump memory from the point where the application is loaded. Next step is to replace encrypted binary data with unencrypted ones. The last thing is to change the flag which determines app encryption. Now, you can use a class-dump application to fetch all the headers with class names, properties and public methods. The whole process is not complicated, but it obviously requires some terminal skills and technical knowledge about the memory and iOS system environment. Things get easier when you use Clutch — a tool which provides the whole process in one line.
Having that information you can attach application process to the debugger and use i.e. Cycript to make some call inside the application. And again, there are applications like Snoop-it, which simplify this procedure. You can install it on iOS device and choose the application you want to access. It created HTTP service which enables you to see app’s graphical structure, invoke methods, check the view hierarchy, hide views, etc. You can even display keychain items or see the network traffic and methods invocations with params.
At this point, you may assume that there’s no chance fully secure your app. And you are right. The mobile application will never be 100% safe. The difference between a server and mobile security is pretty huge. To be able to get data from the server, you need first to get access to it, which is the hardest part. On a mobile device, things are way simpler, because, actually, the device is in your hand. This is why the main goal of mobile device security on is to detect that someone is working on the application, delay the attacker and remove all the sensitive data. Let me point a few things you should consider to protect your app better.
How to play with an attacker? — the rules of the game
- Use low-level API. For things like encryption C, style functions are better than high-level API, as they are much more complex and harder to be replaced with e.g., method swizzling. It’s also good to use inline functions or macros to make things more complicated for the attacker.
- Avoid storing any keys, tokens or passwords in the plain text. It doesn’t matter if you’re planning to store them in the info plist, separate file, or inside the app — it’s always better to keep them encrypted and make one more step before using them.
- Use expiring tokens for authentication. Especially if you want to store them somewhere. If the token expires, it gives you the time to delay the attacker.
- Use SSL certificate authorisation. If the application sends a lot of sensitive data using SSL connection, it’s good practice to provide it with authorisation certificates. More than often users just connect to open network and simply ignore the alerts. As a result, a lot of them accept the unauthorized SSL certificate, which makes the data easy to read with the proxy.
- Clear the sensitive data. Removing files doesn’t clear data from the file system. It just deletes the reference. If you want to make sure the data are removed, you should overwrite them with zeros (or some random data), and unlink the file. Consider applying this solution also to the rows in a database.
- Use an obfuscation. Obfuscating class, protocol, property and method names is an important element of app security. It is much harder for the attacker to succeed if the name consists of random characters. In this situation, he needs to check methods by params or behaviour which takes a lot of time and effort. You can also obfuscate tokens and API keys inside the application to prevent them from being fetched as a string from a binary.
- Check if the app is running on a jailbroken device. You can do so by accessing the path you usually can’t use or making some system actions like fork process. There are a lot of different ways to check that. Don’t rely on just one condition — combine a few methods together for better safety.
- Make sure your app is connected to the debugger. In the application process, there is a flag that returns proper information about debugger connection. But it’s not wise to rely on it. As always, there are plenty of workarounds which may cause misinformation.
- Don’t make your work obvious. Play with the attacker. It’s a good idea to make some methods with a fake name, e.g.
-(BOOL)authenticateUser:(BOOL)auth. Fake methods may change some encryption keys, delete user data or inform the server about the attack. If you detect that someone is trying to attack your app, it is better to change app’s behaviour than to crash or exit the app. The longer the attacker keeps trying to break the app, the more data you’ll be able to secure.
- Check the Keyboard Cache. Inside an application, there is a keyboard cache which, in some cases, can cause leaks of the sensitive data. Obviously, there are some exceptions when the Keyboard Cache is not used, e.g:
- Secure text fields,
- Text fields with numbers only,
- Text fields with a disabled autocorrection.
- Hide the sensitive data. When entering the background, apps make screenshots to display the information without the need of keeping the application launched. Consider hiding or blurring the text, if your app’s using sensitive data (e.g. banking apps).
Keep in mind that even combining the described techniques don’t guarantee that your data are safe. They just prolong and complicate the process of attacking your app. There is no option to make the mobile app as secure as web services. When detecting the attack, clear the sensitive data and keep the attacker convinced that he’s still moving forward.