Top 12 advices on how to develop mobile app securely
More than ever, people are using their mobile device as their primary means of accessing the Internet. This provides not only unparalleled access to information, but also millions upon millions of applications built by third party developers. This platform approach enables users to experience great apps built by developers both large and small. However, this decentralized platform approach only works if there are strong, industry-wide best practices around important app basics such as security.
For everyone who couldn’t make the forum yesterday, we have documented some of the best practices for developing on Android and iOS, and we’re excited to share them with other developers. From the outset, it is important to note that making apps that are secure on Android and iOS is hard. When your application behaves in manner that is unintended, it creates security and privacy implications for the end user, and this might not be restricted to the confines of your app, but potentially across the device.
Top risks include malware installed on the phone alongside your app, tools that allow malicious actors to snoop on device activity, and even malicious websites that can trigger actions in your app using custom URL schemes.
The only way to ensure that your application is secure is to engineer your application for security from the ground up. Here are some recommendations to reduce vulnerabilities in your application:
1. Use HTTPS in a secure way
HTTPS can help you protect the privacy of user data against a man-in-the-middle attack, which could manifest as snooping on data and stealing user sessions on the network. However, to obtain this protection your app needs to perform several steps to verify the server to which it is connecting, and this process is very error-prone. Even a small mistake in verification can result in no protection at all. Read more here – http://crypto. stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
Instead of using the SSLSocketFactory classes, you should use APIs like HttpsURLConnection, which are simpler to use and perform the correct verification steps on your behalf. HttpsURLConnection also adds features (including TLS tickets and SNI headers, which only work correctly after Jellybean) to the HTTPS connection that gives you better performance than using raw SSL sockets. It should always be better to use this API.
Similarly, on iOS it is preferable to always use the high level API NSURLConnection for network requests. Lower level APIs such as CFStream need explicit and often error-prone configuration of SSL.
Android and iOS
To debug network requests with a proxy, such as Charles, you may prefer manually installing a SSL certificate in your testing device rather than using
preprocessor variables and debug-only code to deactivate SSL validation. See more – http:// www.charlesproxy.com/documentation/faqs/sslconnections- from-within-iphone-applications/
2. There are No Client Secrets
Often, developers will spend time trying to obfuscate secrets in the application, which will be used to either authenticate their app to their server or to perform a client-side OAUTH flow.
Trying to obfuscate a secret in Android and iOS clients is a futile effort as the secrets can always be recovered using the abundance of reverse-engineering and debugging tools available for APKs (https:// code.google.com/p/android-apktool/), Java (http://en.wikipedia.org/wiki/JAD_(JAva_Decompiler)), and Objective C (http://www.fscript.org/).
a. Authenticating an app to your server
Often the goal of authenticating the app to the server is to prevent users from getting phished. A good solution to phishing is to support a twofactor
authentication for your application. Facebook login approvals (https://www.facebook.com/note.php?note_id=10150172618258920) is an example of
a large scale two-factor authentication solution that millions of people use daily.
Do not expose your OAUTH secrets to the world via your client application. Store the OAUTH secrets on
your server so that they are indeed secret. To obtain an OAUTH token, the client would then request an end-point on your server that could proxy the token request to the OAUTH provider with the secret, and then, return the token to the client. Once the client obtains the OAUTH token, it can directly make requests to the OAUTH provider.
Some applications use Android WebViews and store cookies in the WebViews to access the remote servers. You should restrict the web-pages that can load inside your WebView with a whitelist. If you are only going to open pages from your domain in the WebView you should restrict those.
These interactions must be carefully reviewed. In particular,
a. if the webview is meant to browse the web, it should not be given large privileges over the native app;
Other applications can overlay content over your application, and fool users into clicking buttons on your app underneath.To prevent this consider setting the
set Filter Touches When Obscured (http://developer. android.com/reference/android/view/View.html#set FilterTouchesWhenObscured) property to true in your views. This will prevent your application from getting touches when another application is obscuring it.
Proofs of concept exist on iOS as well (http://ww-personal.umich.edu/~yangqi/pivot/mobile_phishing_defense.pdf) although this issue should concern only jailbroken devices.
5. Race Conditions onInstalling Apps
Permission stealing [Android] Other apps that are installed before your app, could steal android permissions (including signature level permissions) that you have declared in your manifest by declaring them before you. Your app will function normally, but as a result of this, malware that steals permissions could snoop into all of your app’s content providers and other components.
To prevent this, reduce both the exposure of components and also explicitly authenticate the callers of your components.
Stealing of URL schemes [iOS]
Except for a core subset managed by iOS, URL schemes are registered on first-come, first-served basis.
6. Controlling Exposed Features
Activities, services and broadcast receivers [Android]
You should aim to expose as little of your application as possible to other applications that are potentially malicious. Not setting intent-filters on components, or explicitly setting “exported=false,” will cause components to be local to your application. This is the most effective way of protecting components.
Make sure that before any action that changes the state of your app is taken, the user performs a UI action like clicking a button (this is analogous to CSRF protection in web applications). It is dangerous to perform a write action based on an intent extra passed into a component.
Exposed URL schemes [iOS] Similarly, iOS apps should not perform state-changing actions on processing URLs without asking for confirmation from the user.
7. Watch Out for Internal URL Schemes.
In addition to exposed URL schemes, it is common to define custom URL schemes internally to an iOS or Android app so as to let trusted sources trigger specific actions.
When using custom URL schemes in intent filters, be cognizant of the fact that they can be triggered by not only apps installed on the device, but also malicious websites that the user opens in the browser by simply clicking on a link. This triggers an ACTION_VIEW intent for the URL that was clicked, so that the user does not need to install malware for the malware to exploit a particular component if it has another vulnerability.
Make sure to distinguish internal URLs created by trusted sources from public URLs callable by external apps or made clickable in user contents. The library class NSDataDetector does not restrict the schemes of URLs detected in user contents.
8. Authenticating Callers of Components
Consider calling activities that need to know their caller using startActivityForResult(). The calleeActivity can then enforce the identity of the caller using getCallingPackage()and ensures that is non-null and the package that it expects. A signature check using PackageManager is the most effective way of ensuring the caller is from the same app family as the callee.
b. Content Providers
The user id of the caller can be obtained using Binder. getCallingUid(), and can be used for permission enforcement via signature checks.
c. Broadcast Receivers
There is no current way to get the identity of the initiator of the broadcast. For system broadcasts, ensure that you check the action string of the incoming intent to make sure an intent is coming from the system.
Services can enforce the callerusing Binder. getCallingUid() and using signature checks. However services using the messaging IPC mechanism cannot get the caller uid in the handleMessage() callback. Consider using AIDL-based service calls for exposed services.
Rather than UIApplicationDelegate:application:handle OpenURL:, you may want to implement UIApplication Delegate:application:openURL:sourceApplication:anno tation: and use the sourceApplication to authenticate a URL caller over time. To mitigate spoofing of callers’ URL schemes, the Facebook SDK also lets callers to the main app choose an encryption key for their response.
9. Use explicit intents andIntent hijacking
If private data is being transmitted in an intent, use explicit intents. Explicit intents ensure that the callee receiving the intent will be the one that the caller intended to receive the intent.
Android provides ways to call components using implicit intents, however, keep in mind implicit intents could allow a malicious application to hijack the intent.
If using implicit intents, you should dynamically resolve the receivers of the intent and perform signature checks before sending the intent. “setPackage” is also an option, which restricts the package that can receive an intent. However, this works only after Ice Cream Sandwich.
10. Open redirects
You could protect all your components with permissions and checks, however if there exists even one component in your application that takes a component as an input and redirects to that component, this could be used to circumvent all checks. Avoid this practice at all costs.
11. SQL injection
SQLLiteQueryBuilder is a standard way of building SQL queries for Android. However even though it seems to be safe against SQL injection attacks, underneath the hood its imply concatenates strings. This allows attackers to insert arbitrary clauses into the SQL statement.
You must carefully sanitize user input strings to content providers that are exposed.
You should refrain from constructing SQL query strings directly and instead use a more abstract framework such as EGODatabase or FMDB.
12. Language-Based Vulnerabilities[iOS]
Objective C is susceptible to a variety of programming errors that can be exploited:
* C fragments are vulnerable to the classical C vulnerabilities such as buffer overflows.
* Zombie objects may be exploited.
* User-dependent inputs occurring in format strings, selectors, or regular expressions may be exploited.
* It is important to keep in mind that static types appearing in the code are not enforced at runtime.
* Returning nil values on failures and unimplemented selectors is often ok. Yet, unexpected nil values can cause a crash with some library functions, and can yield unpredictable results in general (for instance [nil isEqualToString:nil] == 0).
ِAbout The Author
Alex Rice, a security engineer at Facebook