Skip to main content

Command Palette

Search for a command to run...

Flutter App Security Best Practices: Protecting Your Apps from Modern Threats

Updated
7 min readView as Markdown
Flutter App Security Best Practices: Protecting Your Apps from Modern Threats
E

Software Engineer | Content Creator

Flutter makes it easy to build beautiful cross-platform applications, but security is often overlooked until it's too late. Whether you're building a small personal project or a large-scale production application, implementing security best practices is essential to protect user data, APIs, and business logic.

In this article, we'll explore the most important Flutter app security techniques, including secure storage, API key protection, certificate pinning, root/jailbreak detection, code obfuscation, and more.

Why Flutter App Security Matters

Mobile applications frequently handle sensitive information such as:

  • User credentials

  • Authentication tokens

  • Payment information

  • Personal data

  • API keys

  • Business logic

Attackers can reverse-engineer APKs, intercept network traffic, manipulate local storage, or run apps on rooted devices. Without proper security measures, your application becomes an easy target.

Remember:

Security is not a single feature—it's a combination of multiple protective layers.

1. Never Store Sensitive Data in SharedPreferences

Many developers make the mistake of storing tokens and passwords in SharedPreferences.

Bad Example

final prefs = await SharedPreferences.getInstance();
await prefs.setString("token", accessToken);

Data stored in SharedPreferences can often be accessed on rooted devices.

Use the flutter_secure_storage package.

dependencies:
  flutter_secure_storage: ^9.2.2

Store data securely:

final storage = FlutterSecureStorage();

await storage.write(
  key: 'access_token',
  value: token,
);

Read data:

final token = await storage.read(
  key: 'access_token',
);

Benefits

  • Android uses Keystore

  • iOS uses Keychain

  • Encrypted storage

  • Resistant to casual data extraction

Best suited for:

  • JWT tokens

  • Refresh tokens

  • User credentials

  • Encryption keys

2. Protect API Keys

One of the most common mistakes in Flutter apps is hardcoding API keys.

Avoid This

const apiKey = "sk_live_123456789";

Even after compilation, attackers can extract strings from your APK.

Better Approach: Use Environment Variables

Use flutter_dotenv.

dependencies:
  flutter_dotenv: ^5.1.0

Create:

API_URL=https://api.example.com

Load:

await dotenv.load();

final apiUrl = dotenv.env['API_URL'];

Important Warning

Environment variables do NOT fully protect secrets.

Since .env values are bundled with the application, attackers can still extract them.

Best Practice

Keep sensitive secrets:

  • On the backend

  • In server-side environments

  • Never inside the mobile app

Example:

Instead of:

Flutter App → Third Party Service

Use:

Flutter App → Your Backend → Third Party Service

This prevents exposing private API keys.

3. Implement Certificate Pinning

HTTPS alone isn't always enough.

An attacker can install a malicious certificate on a device and perform a Man-in-the-Middle (MITM) attack.

Certificate pinning ensures your app communicates only with trusted servers.

Using Dio Certificate Pinning

Example:

final dio = Dio();

(dio.httpClientAdapter as IOHttpClientAdapter)
    .createHttpClient = () {
  final client = HttpClient();

  client.badCertificateCallback =
      (cert, host, port) {

    final expectedSha256 =
        "YOUR_CERTIFICATE_HASH";

    return cert.sha256 == expectedSha256;
  };

  return client;
};

Benefits

  • Prevents MITM attacks

  • Blocks rogue certificates

  • Increases trust in API communication

Things to Consider

Certificate pinning requires maintenance.

When your SSL certificate changes:

  • Update your app

  • Publish a new version

Many companies pin public keys instead of certificates to simplify renewals.

4. Detect Rooted Android Devices

Rooted devices provide attackers with elevated privileges.

Attackers can:

  • Modify application files

  • Bypass security checks

  • Read protected storage

  • Hook app functions

Using Root Detection Packages

Example package:

dependencies:
  flutter_jailbreak_detection: ^1.10.0

Check root status:

bool isJailBroken =
    await FlutterJailbreakDetection.jailbroken;

If root is detected:

if (isJailBroken) {
  showSecurityWarning();
}

Depending on the application:

  • Warn users

  • Restrict sensitive features

  • Block login completely

Especially important for:

  • Banking apps

  • Healthcare apps

  • Financial platforms

5. Detect Jailbroken iPhones

Jailbroken devices remove Apple's security restrictions.

Risks include:

  • Runtime manipulation

  • Keychain access

  • Network interception

  • App tampering

Use the same package:

bool isJailBroken =
    await FlutterJailbreakDetection.jailbroken;

6. Obfuscate Flutter Release Builds

Flutter code can be reverse-engineered.

Without obfuscation:

  • Class names remain visible

  • Function names remain readable

  • Business logic becomes easier to analyze

Enable Obfuscation

Build release APK:

flutter build apk \
--obfuscate \
--split-debug-info=build/debug-info

Build App Bundle:

flutter build appbundle \
--obfuscate \
--split-debug-info=build/debug-info

Benefits

  • Makes reverse engineering harder

  • Protects business logic

  • Hides symbol names

Note

Obfuscation does not provide complete protection.

It simply increases the effort required to analyze your app.

7. Disable Debugging in Release Builds

Debugging tools can expose internal application behavior.

Ensure:

android:debuggable="false"

Release builds generated by Flutter typically handle this automatically.

Always verify before publishing.

8. Secure API Communication

Always use HTTPS.

Never send:

  • Passwords

  • Tokens

  • Personal information

over plain HTTP.

Force HTTPS

Bad:

http://api.example.com

Good:

https://api.example.com

Additional Recommendations

Use:

  • TLS 1.2+

  • Strong ciphers

  • HSTS on backend

  • Certificate pinning

9. Implement Token-Based Authentication Properly

Avoid storing user passwords locally.

Use:

  • JWT Access Token

  • Refresh Token

Flow:

Login
  ↓
Access Token
  ↓
API Requests
  ↓
Token Expired
  ↓
Refresh Token
  ↓
New Access Token

Store tokens using Secure Storage.

10. Protect Against Screen Recording & Screenshots

Some applications contain highly sensitive information.

Examples:

  • Banking

  • Medical records

  • Crypto wallets

Android

Prevent screenshots:

window.setFlags(
    WindowManager.LayoutParams.FLAG_SECURE,
    WindowManager.LayoutParams.FLAG_SECURE
)

Flutter package: flutter_windowmanager

Benefits

Prevents:

  • Screenshots

  • Screen recordings

  • Recent apps preview leakage

11. Verify Application Integrity

Attackers often modify APKs and redistribute them.

Integrity checks help detect:

  • Tampered APKs

  • Modified applications

  • Unauthorized distributions

Android Play Integrity API

Google recommends using:

Google Play Integrity API

It helps verify:

  • Genuine app installation

  • Genuine device

  • Untampered application

12. Avoid Logging Sensitive Information

Never log:

print(password);
print(token);

Bad logs can expose:

  • User credentials

  • Session tokens

  • Personal data

Safe Logging

debugPrint(
  "Login successful"
);

Use logging only in development environments.

13. Encrypt Sensitive Local Data

For highly sensitive applications:

  • Banking

  • Healthcare

  • Enterprise apps

Consider encrypting local databases.

Popular choices:

  • SQLite + SQLCipher

  • Encrypted Hive

  • Custom encryption layers

14. Secure Firebase Configuration

Many Flutter applications use Firebase.

Common mistakes:

  • Open Firestore rules

  • Public Storage buckets

  • Weak Authentication rules

Always configure:

Firestore Rules
Storage Rules
Authentication Rules

before releasing your app.

15. Protect Against Reverse Engineering

Remove unused code

flutter build appbundle

Use tree-shaking.

Minify Android code, Enable

minifyEnabled true
shrinkResources true

with ProGuard/R8.

Security Checklist Before Publishing

Before releasing your Flutter application:

✅ Use Secure Storage

✅ Store tokens securely

✅ Use HTTPS

✅ Implement Certificate Pinning

✅ Detect Root/Jailbreak

✅ Obfuscate release builds

✅ Hide sensitive API keys

✅ Enable Play Integrity API

✅ Disable screenshots for sensitive screens

✅ Avoid logging secrets

✅ Encrypt sensitive local data

✅ Configure backend security properly

✅ Verify app integrity

Conclusion

Flutter provides an excellent framework for building cross-platform applications, but security is ultimately the developer's responsibility. No single technique can completely secure an application. Instead, you should adopt a layered security strategy that combines secure storage, encrypted communication, root/jailbreak detection, certificate pinning, code obfuscation, and backend validation.

The goal isn't to make your application impossible to attack—it's to make attacks significantly more difficult, expensive, and detectable.

By implementing the practices discussed in this article, you'll dramatically improve the security posture of your Flutter applications and better protect both your users and your business.

S

Excellent security checklist! I particularly appreciate that you emphasized layered security rather than presenting any single technique as a complete solution. Too often developers rely solely on HTTPS or obfuscation, but real application security comes from combining secure storage, backend validation, certificate pinning, integrity checks, and proper authentication.

I also liked the clarification about environment variables they're useful for configuration, but they shouldn't be treated as a secure place for secrets in mobile apps. That's a misconception many developers still have.

This is a practical guide that every Flutter developer should review before publishing a production app. Great work! 👏