Nowadays, it is hard to imagine life without mobile devices. We use them everywhere to facilitate our lifestyle. They help us to communicate with each other, have fun, and even make purchases. We use them at home and at work. These devices accompany us during our business trips and vacations. Our children use them for educational purposes and for amusement. They are part of our daily lives.
A mobile device usually has some operation system (OS) installed on it. The OS allows us to perform basic operations with the device, namely make calls, send SMS, take pictures, surf the Internet, etc. Feature set of OS can be expanded with installation of additional specific mobile apps. They can store our settings, history, passwords and other sensitive data. They track our activity to detect our preferences. Apart from that, they transmit user data to a remote service endpoint to synchronize. Every action, performed by such apps, needs to be properly protected from potential data breaches.
The problem of mobile application security is not new. It originated in early 2000s, leading to the foundation of Open Web Application Security Project (OWASP). The Mobile AppSec Verification Standard (MASVS) was developed as a part of this project. That document explains the process of developing secure applications. It contains recommendations from the architecture design to the build setting requirements. The document provides the following two security levels: for all mobile applications (L1) and for the applications that handle highly sensitive data (L2).
In the this article, we cover the most significant aspects of developing secure mobile applications for iOS and Android OS. These aspects include local data storage requirement; authentication and session management requirements; network communication requirements; and resiliency against reverse engineering.
Local data storage
According to MASVS, an application must use system credential storage facilities to store sensitive data, such as user credentials or cryptographic keys (recommendation 2.2).
Usually, Android OS uses account.db database to keep application tokens. A root permission is necessary to access that database. The assumption that account.db remains inaccessible holds true only for the newest Android version, because older Android versions may contain known vulnerabilities, which can be exploited to get the root permission. Anyway, an application should not keep user credential in that database as a plain text. Instead, it needs to use tokens that become expired within some time or after user logging out.
It is also worth pointing out that there are ways to access user data without any credentials. We developed such a way at Apriorit to use with legitimate parental control and DLP solutions, which you can read in this article. However, similar methods can also be used by perpetrators with malicious purposes, so you should always be careful.
In most scenarios, an iOS application keeps user credentials and tokens in the keychains. Those tokens and credentials can be backed up with iTunes. Unless the device is jailbroken, the tokens and credentials can be acquired from the encrypted backup only. However, if an iOS device does not have iTunes password, an attacker can always set the password they know, and then obtain the backup encrypted with a known password. Therefore, we do not recommend that user credentials be stored in keychain in plain format too. Moreover, no sensitive data must be backed up in case of the security level L2 (recommendation 2.8).
The most popular local storage for both iOS and Android mobile applications is a SQLite database. It is an open source database management system. However, the open source version does not support data encryption. You may implement custom data encryption before writing data to the database. In this scenario, the data is protected, however, the database scheme can be viewed. Another option is to use shareware implementation of SQLite such as SSE, SQLCipher, SQLiteCrypt, etc. Those implementations support data and scheme encryption out of the box. If you implement your own encryption mechanism, be sure to use proven encryption algorithms and trusted libraries such as OpenSSL. It is clear, that neither password nor encryption key must be stored on the device or hardcoded into the application sources.
There is also the possibility that native or third party components of the software create temporary files to cache data. If those files have inappropriate backup settings, unprotected sensitive data may be included into the backup. For instance, we noticed the case when an iOS healthcare application using NSURLRequest class backed up Cache.db file, which contained user login, password and other sensitive data. Therefore, all such components must be investigate for such side effects.
If you want to learn more, check out our other article on using AndroidKeyStore for secure user password storage.
Secure network communication likely is the most important aspect of application security. To exchange sensitive user data between a remote service endpoint and a client application, a secure protocol must be used. TLS is the only protocol recommended by MASVS. It is important that only certificates signed by a valid certificate authority (CA) be accepted.
The standard also suggests using SSL-pining technique for L2 applications. Use of SSL-pining is now a common practice for most network mobile applications. This scheme assumes that a server public key hash is hardcoded into the application sources. Use of SSL-pining protects the application against man-in-the-middle attack. However, it is still possible to develop a fake client-side application. There is no technique to prevent from this. Therefore, you need to develop a server-side application that should never trust a client-side application.
A common practice is to use session tokens instead of transmitting user credentials each time the client sends data. There are two token types in most cases. They are an access token and a refresh token. A client application uses the access token to send requests to a server as depicted in Figure 1.
The refresh token is used by the client to refresh the expired access token. Both access and refresh tokens must be invalidated on user logging out. There are several standardized authorization protocol basing on this principal, i.e. OAuth 1.0, OAuth 2.0. Mentioned protocols allows users to have a single account that can be used for authentication with third-party applications or websites. Vendors often designs their own authorization protocols based on some token management policy.
MASVS-L2 recommends that 2-factor authorization (2FA) be used for critical operations, and different secure communication channels should be provided (SMS, e-mail, calls, etc.).
Additional information may be used to authenticate a user. For instance, using device serial number, it is possible to limit a number of user devices that can communicate with a service endpoint.
It is important that a client is always using an original mobile application supplied by a vendor. Besides, it must be extremely difficult for a hacker to develop a fake mobile application that has some changes in its logic to stole or compromise user data. Therefore, a mobile application must be resilient to reverse engineering tools.
Software protection is considered an additional mechanism, and never must be used in place of security controls. Do not develop your own cryptographic algorithms with the hope that they remain secret under the code protection mechanism. The same concern holds true for any hardcoded values, keys, queries, etc. Software protection just makes the life of a hacker much tougher. Its only purpose is to increase the cost of reverse engineering and make it economically unreasonable.
The common requirements towards reverse engineering include code obfuscation, resource encryption, protection against patching and repacking, root permission detection, emulator detection, detection of hooking frameworks, detection of debugging tools, etc. A developer should not reinvent the wheel designing they own software protection mechanism because there are many special tools. However, good tools are not freeware. Even if you use a third-party protection software, be sure to test the protection of your application manually.
To check for the code obfuscation you may use IDA for ipa-packages (iOS) and JEB or BytecodeViewer for apk-packages (Android). There are also plenty of online tools to decompile apk packages into java classes. A typical obfuscator renames classes, methods and variables into the format that is difficult to analyze by a human as depicted in Figure 2.
Good obfuscators not only obfuscates the source code, but also encrypt strings with complicated encryption mechanism. The encryption key for each string may depend on multiple parameters.
If you use CLI, e.g. Mono, to investigate the obfuscation you may use JetBrains dotPeek.
To patch/repack an apk-package you may use apk-tools together with the tools from Android SDK (keytool, jarsigner, zipalign).
Another important aspect is the investigation of the Internet traffic your application generates. Fiddler is likely the best choice for this. If your iOS application uses SSL-pining, you may use SSL Kill Switch 2 to try to overcome it. In this case, you need a jailbroken device.
- Mobile application security is vital for the applications that handle user data. To test the security level of your application, we recommend that Mobile AppSec Verification Standard (MASVS) should be used.
- The most important aspects of the mobile application security are local data storage security; authentication and session management; network communication, and resiliency against reverse engineering. To provide a necessary security level, only proven algorithms and libraries must be used.