Most mobile apps are not insecure because of advanced attacks. They're insecure because of simple decisions.

Rethinking Mobile App Security

When developers think about security, they often think in:

  • HTTPS
  • encryption
  • authentication

But security doesn't come only from them.

It comes from the decisions you make across your system.

Every choice — on mobile, backend, or architecture — either reduces your attack surface… or silently increases it.

The Problem

In many apps, security is treated like a checklist:

  • "We're using HTTPS"
  • "We store tokens"
  • "We added authentication"

But real systems don't fail only because something is missing.

They fail because something was designed incorrectly.

A Better Mental Model

Instead of asking:

"Did I add security?"

Ask:

"Where can my system be attacked?"

This shifts your thinking from security features → to architecture.

My golden rule for the security model is:

All system's components must not trust each other before proper validation.

System Design Decisions Define Your Security

If there's one rule to remember, it's this:

Never trust the client.

Your backend is the only place you fully control. And the decisions you make there define how secure your system actually is. Statistics show that lots of the cyber attacks starts from a compromised user client, that's why you should protect your backend from your clients and validate their behaviors before executing their requests.

❌ Don't Call Third-Party APIs Directly from the App

This is one of the most common and dangerous patterns.

App → Third-party API

It works. It's simple. But it comes with hidden risks.

What Goes Wrong

  • API keys must exist inside the app
  • keys can be extracted (reverse engineering)
  • requests can be replicated outside your app

Once exposed, your backend or third-party service can be abused without limits. And fixing this might be disruptive for the whole system.

Use Your Backend as a Gatekeeper ✅

Instead, structure your system like this:

App → Your Backend → Third-party API

Note: This solution might not be applicable with all third parties services, but it should be considered at least before used.

Why This Matters

1. Secrets Stay Safe

API keys shall live only on your server, not inside the app.

2. Full Control Over Requests

You can:

  • validate input
  • enforce business rules
  • apply rate limiting
  • monitor usage

3. Centralized Logic

All critical logic stays on the backend:

  • easier to update
  • harder to exploit

Validate Everything Server-Side

A common mistake is trusting the client:

  • sending calculated values
  • enforcing logic on the app
  • assuming requests are "valid"

The client is an untrusted environment.

Always:

  • validate inputs
  • verify permissions
  • enforce rules server-side

Enforce Strict Backend Security Rules

Even if your backend sits between your app and external services, that alone is not enough.

Access must be controlled — not just routed.

Every service exposed through your backend should be protected by strict security rules:

  • Validate who is making the request
  • Verify what they are allowed to access
  • Restrict data based on ownership or permissions

Whether you're using a custom backend or a managed service, relying on default or permissive rules is a common mistake.

A secure backend does not assume trust — it enforces it.

Poorly defined rules can lead to:

  • unauthorized data access
  • cross-user data leakage
  • unintended exposure of sensitive resources

Security rules are not an optional layer. They are part of your backend contract.

When Real-Time Is Required: Controlled Direct Access

There are cases where routing everything through your backend is not practical.

Real-time systems — like chat — often require:

  • low latency
  • persistent connections
  • instant updates

In such scenarios, you might need to allow the mobile app to communicate directly with services like Firebase.

But this introduces a new challenge:

How do you allow direct access without exposing your system?

The Risk

If identifiers or access paths are predictable (e.g., based on user IDs):

  • they can be guessed
  • accessed by unauthorized users
  • used to read or write data they shouldn't see

The Safer Approach

Access to real-time resources must be:

  1. Undeterministic
  • Not guessable
  • Not derived from public identifiers

2. Generated by the backend

  • Issued per session or per context
  • Delivered securely to the client

Example

Instead of:

chat_room_id = hash256(user1_id + user2_id) ❌ 

Use:

chat_room_id = random_secure_token generated by backend ✅

Why This Matters

This approach ensures:

  • only authorized users can access the chat
  • no predictable patterns can be exploited
  • no accidental cross-access between users

The backend remains the source of truth — even when the client connects directly.

Important

Even with this setup:

  • enforce strict backend or service-level security rules
  • validate membership and permissions
  • never rely on identifiers alone

Key Insight

Direct access is not always the problem, uncontrolled access is.

⚖️ Trade-offs

These decisions are not free:

  • more backend complexity
  • additional infrastructure
  • slightly higher latency

But in return, you get:

  • control
  • visibility
  • real security

A Simple but Critical Insight

If your backend trusts your app, your system is already broken.

👀 What's Next

In the next part, we'll move to the other side:

Mobile app decisions — what can we do to protect our client app?

Including:

  • secure storage
  • encryption
  • certificate pinning
  • minimizing exposure