Flutter Security 101: Restricting Installs to Protect Your App from Unofficial Sources
Last updated
Last updated
Company
General Terms and ConditionsIn today’s mobile app ecosystem, ensuring your app is secure from piracy, tampering, and sideloading is more important than ever. With unofficial app stores and third-party platforms on the rise, developers face the risk of their apps being stolen, modified, or misused, often leading to revenue loss, security breaches, and reputation damage. One simple but effective measure to safeguard your app is enforcing install source restrictions, ensuring it only runs if downloaded from official stores like Google Play or the Apple App Store. This article explores how you can implement these checks and why it’s crucial for app security.
Distributing an app through unofficial channels opens the door to numerous security threats, many of which could have devastating consequences for both the developer and users. Unauthorized installs can lead to significant breaches in security for several reasons:
Tampered versions of the app
Lack of official updates and security patches
Data leaks and privacy concerns
Exploits for ads or in-app purchases
Gateway for broader attacks
Commonly, fake applications are installed through the internet browser, file manager, cloud storage, or various messaging apps.
One common scenario is that the app being installed has been tampered in order to skip verifications of some kind or in order to add malicious code to it. As an example, an attacker can use apktool
to decompile the apk:
This gives back a smali version of the app that can be changed later on. Think of smali
code like an assembly-like language that is a low-level representation of the compiled Java code. That can be modified by maybe adding a key logger function of some sort.
Than is as simple as repacking the app with apktool
and then resign the apk
This high-level example shows how dangerous it can be to install an app like this for both developer and user. Users who unknowingly download these tampered versions may be exposed to malware, spyware, or data-stealing mechanisms that compromise their personal information. This type of unauthorized access could include reading sensitive files, intercepting user data, or even hijacking user accounts. Developers can be harmed both in terms of their reputation and earnings. Modified app versions may disable ads, unlock premium features for free, or provide unauthorized access to paid content.
One basic strategy is to check the install source every time the user launches the app and react accordingly.
Let’s see a quick and easy example using Flutter. Keep in mind that we will write some native code for Android and iOS, so you can use the same code if your app is native only or if you want to use it in any other framework.
So first of all, let’s create a new Flutter project with flutter create check_install_source
. You can remove the main.dart
file entirely and replace it with the following, starting with the necessary imports and the classi main declaration:
Then we can create a MyApp
class
In the actual MyAppState
we can implement a simple build
method and the initState
:
Now let’s add a new method called _checkInstallSource in the initState
So that we can implement it as following:
What’s happening here is that we are calling specific native function using flutter’s method channels (https://docs.flutter.dev/platform-integration/platform-channels) so that we can perform some action in the native side. Of course we are catching exceptions that may occur.
When we call getInstallerPackageName
**Android method we will ask what the install source is. In this case we are checking against com.android.vending that’s the Google Play Store but you can also check plenty of other alternative stores like Samsung Galaxy Store com.sec.android.app.samsungapps.
On the other hand, when calling validateAppStoreReceipt
iOS method we are checking that an App Store receipt is present. Even on free apps, Apple attach a receipt file to verify the authenticity of the executable. Of course just checking if the receipt is there or not could not be enough so you can perform additional verification or send receipt to your server for validation (https://developer.apple.com/documentation/appstorereceipts/validating_receipts_on_the_device).
Now, before checking kotlin and swift code, let’s see what we can do with those informations and let’s implement the _showErrorAndExit()
method.
Keep in mind that’s just an example to alert the user. Exiting an app with exit(0)
it’s not usually recommended because Apple may reject your app when submitting it to the AppStore.
Now open the MainActivity.kt file in Android folder and swap the content with necessary import first:
and than change the MainActivity class as following:
In this chunk of code we are implementing Flutter method channel in Android counterpart, getting ready to listen for the same method getInstallerPackageName
that we implemented in Dart. Using packageManager
we can get the installer package name and pass it back to Dart.
We can move to iOS folder opening AppDelegate.swift and adding imports:
We can proceed editing didFinishLaunchingWithOptions method to let Swift know what method need to be respond to:
Last step is to implement the isValidAppStoreReceipt() method in the AppDelegate class:
Your app should now be able to check the install source and force exit if it’s an unofficial source (in this example).
Even if you have verified the install source of an app this is just the initial stage of ensuring that only genuine and authorized versions are installed, developers still need to undertake other steps to ensure that their apps are safe. Here are some effective strategies and tools that developers can leverage to enhance security.
Flutter / Dart are typically more resilient against reverse engineering as the code is minified during the compilation (not really obfuscated). It's common to offload sensitive parts of code to domains that can be obfuscated more easily: Java/Kotlin, Swift, and especially C/C++ languages can be obfuscated by ready-made obfuscators.
Code obfuscation remains one of the easiest ways by which one can protect his or her application. Consumer objectives can be achieved using tools such as ProGuard for Android or LLVM Obfuscator for iOS because such tools distort code within the app, making it impossible for an attacker to understand what the app does. While renaming classes, methods, and variables, the work of an attacker significantly becomes more complex, depriving him even an attempt to begin to decompile and adjust the internal functioning of the application.
Another interesting project worth checking out ishttps://obfuscator.re, that’s based on
dProtect an Android bytecode obfuscator based on Proguard O-MVLL is an obfuscator based on LLVM that uses the new LLVM pass manager,
-fpass-plugin
to perform native code obfuscation
One must recognize when an app is running in an environment such as a jailbroken iPhone or iPad or a rooted Android device. These devices usually eliminate crucial security components, thus rendering them prone to hacking. There is always the possibility of root and jailbreak detection, so existing applications cannot run within these breeches.
freeRASP (Runtime Application Self-Protection) (https://docs.talsec.app/freerasp) refers to an all-inclusive security solution whereby your mobile application can be monitored in real-time. It goes beyond basic checks like jailbreak or root detection by offering a full suite of security features, including:
Integrity Check: Identifies the state or level of modification of the app in order to determine if it has been modified in anyway. Debugging Detection: Recognizes whether in a specific app it is currently being debugged, or, for instance, during reverse engineering. Repackaging Protection: They also shield users against other attackers altering and repackaging their applications. Anti-Hooking: Intercepts and protects against such tool as Frida from injecting their code into the app during its execution. With the help of freeRASP, developers can prevent complex threats, including tampering, reverse engineering, and runtime manipulation. The application is free of charge and comes with powerful addressing security options compared to other powerful addressing security options that can easily be incorporated into existing mobile applications.
It is, therefore, important to consider multiple levels of security when developing applications for the current mobile environment. Verifying install sources is a good start, but by using tools such as freeRASP, runtime protections, and server-side checks, developers can offer a much safer environment for the applications. This shields the users from such applications and possible data leakage and your brand and business from the possible repercussions of a malicious app.
Marco Galetta, Senior Software Engineer
Experienced and dedicated Mobile App Developer with impressive expertise in Flutter Framework. Directs the design, development, and implementation of mobile applications and delivers products ahead of schedule.