<FlutterSolution/> flutter · dart · clean architecture

Flutter Prep #26 Fintech-Grade Security in Flutter: A Checklist Every Senior Candidate Should Know

Fintech-Grade Security in Flutter: A Checklist Every Senior Candidate Should Know

Why "we just use HTTPS" is no longer enough for modern product interviews, and the specific controls you need to name out loud.

1. Why Every App Needs a "Fintech" Standard

Security questions are no longer reserved for banking or healthcare roles. Whether you are building an e-commerce checkout, a ridesharing app, or a social network handling personal messages, the expectation for data handling has risen industry-wide. Interviewers at top product companies will probe these fundamentals regardless of the app's category.

In a system design or architecture interview, you'll be asked to name at least three of these controls without prompting. We'll use the login and transaction flow of a banking app to illustrate, but view this as a defense-in-depth checklist that any senior candidate should be able to run through fluently in about 90 seconds.

Secure Storage
Tokens and PII locked in hardware-backed KeyStore/Keychain.
Cert Pinning
Hardcoded certificate hashes preventing rogue CA MITM attacks.
Code Obfuscation
Deterring reverse engineering of client logic and API structure.
Biometrics + Short JWTs
Tying authentication to device hardware with minimal token lifetimes.
Device Integrity
Verifying OS state via Play Integrity / App Attest.

2. Secure Local Storage (Data at Rest)

The cardinal rule of mobile security: Authentication tokens (JWTs, OAuth refresh tokens) and Personally Identifiable Information (PII) should never go into SharedPreferences, SQLite, or plain text files. Those mechanisms are entirely unencrypted and trivially easy to extract from a rooted/jailbroken device or an iTunes/Google Drive file-system backup.

Instead, use the flutter_secure_storage package. This relies on the iOS Keychain and Android KeyStore. What makes these different? They are platform-level secure stores, often backed by hardware (like the Secure Enclave on iOS), meaning the OS enforces strict access controls, and the data is encrypted at rest using keys the app itself never directly sees.

Dart
final storage = FlutterSecureStorage();

// ONLY write tokens here, not SharedPreferences
await storage.write(key: 'refresh_token', value: tokenData);

// Recommended: configure Android to require screen lock
final options = AndroidOptions(encryptedSharedPreferences: true);

3. Certificate/SSL Pinning (Data in Transit)

HTTPS encrypts data in transit. But what happens if an attacker compromises a Certificate Authority (CA) on a user's device, or tricks a user into installing a rogue corporate profile? Normal HTTPS validation will quietly trust the attacker's fake certificate, allowing a Man-In-The-Middle (MITM) attack to read your banking app's API traffic in plain text.

Certificate Pinning prevents this by hardcoding the expected SHA-256 hash of your server's public key directly inside the Flutter app. If the server presents a certificate that doesn't match the pin—even if the OS says it's valid—the app refuses the connection.

The honest trade-off to state in an interview: Pinned certificates eventually expire. If your DevOps team rotates the server's certificate without first pushing an app update containing the new pin, you will literally break the app's networking for 100% of your users until an emergency hotfix passes store review. It is a massive operational risk.

4. Code Obfuscation & Untrusted Clients

Obfuscation makes your compiled Dart code significantly harder to reverse-engineer by replacing class and method names with meaningless symbols.

Bash
flutter build apk --obfuscate --split-debug-info=build/app/outputs/symbols

However, the framing you must use in an interview is this: Obfuscation is a deterrent, not a guarantee. A sufficiently motivated attacker will eventually deobfuscate your client code.

This connects to the most important principle of client-side architecture: The client is entirely untrusted.

πŸ“±
Client
Never fully trusted
Transfer: $5,000
☁️
Server
Re-validates Limit

If your banking app checks if (amount > dailyLimit) on the client side to disable the transfer button, an attacker can modify the local binary to bypass that check. Critical business logic must always be re-validated on the server. The server is where trust actually lives.

5. Biometrics & Short-Lived Tokens

For authentication, use local_auth to prompt for FaceID or Fingerprint before allowing access to sensitive screens. But biometric auth alone isn't enough—it must be paired with a proper token lifecycle.

Standard practice relies on short-lived JWTs (Access Tokens) paired with a Refresh Token. If an access token is somehow intercepted, a short lifetime (e.g., 15 minutes) limits the damage window before the token becomes useless.

For mobile apps, the current standard is OAuth 2.1 using PKCE (Proof Key for Code Exchange). PKCE exists specifically to protect the authorization-code exchange on a platform like mobile, where a static "client secret" cannot be securely hidden in the binary.

6. Root, Jailbreak & Device Integrity

To detect if an OS has been compromised (rooted/jailbroken), use the Play Integrity API on Android and App Attest on iOS. These APIs provide cryptographic proof to your server about the integrity of the device running the app.

But here is the nuanced, senior-level distinction you must make: Gate high-risk transactions, not login itself.

Gating Login
🚫 User is locked out of their entire account due to an OS glitch.
Gating Transactions
⚠️ User can view balance, but requires SMS OTP or secondary device approval to move money.

Why? Because integrity checks have false positives. A legitimate device might fail a check due to a weird carrier firmware update. If you hard-block login on an integrity failure, you permanently lock a real user out of their account. Gating only the transaction limits the blast radius of a false positive.

7. The OWASP Mobile Top 10

You don't need to recite all ten verbatim, but you should be able to rattle off 4 or 5 of these practical categories in an interview:

1. Insecure Data Storage

Storing PII in plain text SharedPreferences instead of Keychain.

2. Insecure Communication

Failing to use HTTPS or omitting Certificate Pinning for critical APIs.

3. Insufficient Cryptography

Using MD5 or SHA1 instead of modern hashing algorithms like bcrypt/Argon2.

4. Client-Side Injection

Trusting deep-link parameters blindly without sanitization.

5. Reverse Engineering

Failing to obfuscate release binaries, leaving API keys exposed.

8. Screen Privacy (The Senior Detail)

A small detail that signals real production experience when mentioned unprompted: preventing screenshots and screen-recording on sensitive screens (like OTP entry or account routing numbers). Using a package like screen_protector (which sets FLAG_SECURE on Android and hooks into UIApplicationUserDidTakeScreenshotNotification on iOS) prevents malware or accidental screenshots from capturing sensitive PII.

9. Secrets & Environment Management

Never commit API keys or signing secrets to source control. Use --dart-define or --dart-define-from-file to inject configuration at build time via your CI/CD pipeline.

Bash
flutter build apk --dart-define-from-file=config/production.json

However, the most important principle for secrets management is a great one-line interview answer: A secret embedded in a shipped client binary is NEVER actually secret. Even with --dart-define, the key ends up in the compiled binary. A motivated attacker can extract it. Therefore, truly sensitive secrets (like your payment provider's private API key) must stay entirely server-side and never ship in the Flutter app at all.

10. Deep Links, Pub.dev, & WebViews

Three final areas to mention to round out your security posture:

  • Deep-Link Hijacking: Another app on the device could maliciously register your custom URL scheme. Always validate the deep link's claimed destination against an allow-listed pattern before acting on it.
  • Supply-Chain Risk: Treat pub.dev packages as an attack surface. In a payments codebase, rely on version pinning, thoroughly review new transitive dependencies before upgrading, and be incredibly cautious about importing low-maintenance packages.
  • WebView Security: If your app embeds a WebView, never expose a JavaScript bridge to untrusted external content, and strictly restrict navigable origins.
🧠 Interviewer's Follow-Up

Q: Why gate high-risk transactions instead of login itself behind an integrity check?
A: False positives. If a legitimate user's device fails a check due to an OS glitch, blocking login completely locks them out of their account. Gating only the transaction limits the damage and allows them to view balances or contact support.

11. Senior-Level Sample Answer

If an interviewer asks: "Walk me through how you would secure the architecture of a new mobile banking application."

"I view this as defense-in-depth across the client, network, and server. For authentication, we'd use OAuth 2.1 PKCE with short-lived JWTs, requiring biometric local_auth to resume a session. For data at rest, any PII or refresh tokens would be strictly stored in the hardware-backed iOS Keychain or Android KeyStore using flutter_secure_storage, never SharedPreferences. For data in transit, we'd implement certificate pinning to prevent MITM attacks, ensuring we have a robust DevOps rotation plan. We treat the client as completely untrusted—so while we'd obfuscate the release binary to deter reverse engineering, all transaction limits and business rules would be rigorously re-validated server-side. Finally, we'd integrate Play Integrity and App Attest, using them to flag high-risk transactions for secondary verification rather than hard-blocking the login flow to avoid false-positive lockouts."
✅ Quick Self-Check

Before moving to the next post, answer this unscripted: Why is injecting an API key via --dart-define still not secure enough for a private Stripe billing key?

Official Resources


Written by Flutter Solution · Covering the Flutter & Dart ecosystem from Mumbai, India · fluttersolution.com
Nachiketa Pandey
// written by

Nachiketa Pandey

Senior Flutter Developer · Cross-Platform & Fintech Applications

Building production Flutter apps at Kotak Neo — clean architecture, BLoC, agentic AI integrations, and fintech-grade security. Sharing everything I learn, one post at a time.

Flutter & Dart Clean Architecture BLoC Firebase FinTech
View Full Portfolio

Comments

Nachiketa
Meet Author// tap to open