Your App Runs on Somebody Else's Phone
That single fact drives every decision on this page. The binary can be taken apart, the device can be modified, and the network in between belongs to nobody you know. Mobile security is about designing for that rather than hoping.
Anything You Ship Inside the App Is Readable
A published app is a file that anybody can download, unpack and inspect. Strings can be listed, resources extracted, network calls watched, and the running app attached to and modified. None of this requires anything exotic.
Obfuscation buys time, not secrecy
Renaming and scrambling code raises the effort from minutes to hours. That is worth having against casual copying, and it is not a place to keep anything that would hurt you if it were published. Treat it as a speed bump with a name that oversells it.
Secrets belong on a server
Third-party API keys, payment credentials, signing secrets and anything with billing attached live on your backend. The app calls your server, your server calls the service. That also means a compromised key can be rotated in one place, without a store release.
The client is a suggestion
Every rule enforced only in the app can be bypassed by editing the app. Prices, entitlements, limits, roles and validation are decided on the server, and the app is treated as an untrusted caller that is usually telling the truth.
Tokens, not credentials
After sign-in the app should hold a short-lived token tied to one user, refreshable and revocable, rather than a password or a shared key. Losing a token then costs one session on one device rather than the account.
Receipts are verified server-side
A purchase confirmed only on the device can be faked. Entitlements are checked against the store from your backend, which is also the only way to handle refunds, cancellations and a second device sensibly. More in monetisation.
Logs leak
Debug logging that prints tokens, payloads or personal data does not stop being readable in a release build unless somebody removed it. Log statements are reviewed before release the same way code is.
What Goes in the Keychain, and What Must Never Ship
Both platforms provide a proper secure store backed by hardware. The mistakes are almost always about using something easier that sits next to it.
Keychain on iOS, Keystore on Android
- Session and refresh tokens, so they survive an update without being readable by anything else
- Encryption keys for any local database you are protecting yourself
- Keys generated in and never leaving secure hardware, released only after a device unlock or a biometric check
- Accessibility set deliberately: available only after first unlock, and not migrated to a new device where that matters
- Cleared on sign-out and on account deletion, including the leftovers from a previous install
Never in the app bundle or plain storage
- API keys and service credentials pasted into a constants file or a build configuration
- Tokens or passwords written to ordinary preference files, which are trivially readable on a modified device
- Anything sensitive in an unencrypted local database or a cached file left in a shared folder
- Secrets committed to the repository, where they persist in history long after being deleted
- Personal data copied into analytics events or crash breadcrumbs because it was convenient
On iOS the keychain survives an app being deleted and reinstalled, which surprises people in both directions — it is a feature for continuity and a bug if you expected a clean slate. We decide that behaviour deliberately rather than inheriting it.
Transport Security, and the Real Cost of Pinning
Encrypted transport everywhere is the baseline, and both platforms now block plain unencrypted traffic by default. The interesting decision is whether to go further and pin.
The baseline, on every project
- Modern encrypted connections only, with the platform exception lists left empty
- No test endpoint, staging host or debug bypass left switched on in a release build
- Certificate validation never disabled, not even temporarily, because temporary code ships
- Sensitive values in request bodies rather than in URLs, which end up in logs and analytics
- Third-party SDK traffic reviewed, because their connections are your responsibility
Pinning: what it costs you
Pinning tells the app to trust only specific certificates or keys for your servers. It stops an attacker who has convinced a device to trust a certificate it should not, which is a real attack on public networks and on managed devices.
The cost is a permanent operational obligation. Rotate that certificate without shipping an update first and every installed copy of the app stops working, including for people who never update. The recovery is a store release, which takes review time you do not control.
So if we pin, we pin properly: backup pins for the next certificate, a renewal date owned by a named person rather than a calendar nobody reads, a remote way to relax the pin, and monitoring that notices before your users do. For a banking or health app that is a fair trade. For a content app it usually adds more outage risk than it removes attack risk.
Face and Fingerprint, Done So They Mean Something
The common implementation checks a face, sets a variable to true and continues. On a device the attacker controls, that variable is a suggestion.
Unlock a key, not a flag
A correct implementation ties the biometric check to a key held in secure hardware, released only on success, and that key then signs or decrypts what you actually needed. Nothing useful happens if the check is skipped.
It is a local gate
Biometrics prove the phone was unlocked by someone the phone accepts. They are not evidence to your server that a particular user authenticated, so the server still relies on a real token and its own session rules.
Always have a fallback
Sensors fail, hands get wet, faces are covered, and some people cannot use biometrics at all. The device passcode fallback is both an accessibility requirement and the thing that stops a lockout becoming a support queue.
Invalidate on re-enrolment
If a new fingerprint or face is added to the device, the stored key should become invalid and the user should sign in again. Otherwise adding a face to a borrowed phone silently inherits access to your app.
Never re-submit a password
Storing the password and replaying it after a successful scan turns a good mechanism into a stored credential problem. If the password must exist somewhere, it exists on your server, hashed.
Ask at the right time
Re-authenticate on the actions that matter — payments, changing details, revealing sensitive data — rather than on every app launch, which trains people to approve without looking.
Jailbreak and Root Detection, and Its Honest Limits
Detection has a place. It is also routinely oversold, and the way it is usually deployed punishes the wrong people.
What it can do
- Flag a device as higher risk, and adjust what it is allowed to do
- Feed a server-side risk score alongside other signals
- Satisfy a compliance or contractual requirement that asks for it by name
- Discourage casual tampering, which is most of the tampering there is
What it cannot do
- Stop a determined attacker, who is using the tools built to hide from it
- Stay reliable, since every OS release changes what the checks can see
- Avoid false positives on unusual but entirely legitimate devices
- Substitute for server-side enforcement, which is the only check an attacker cannot edit
Our default is to detect, report and adapt rather than to refuse. Blocking outright is reserved for apps where a rule or a contract genuinely requires it, and even then the real defence lives on the server.
Data at Rest, on a Phone Left in a Taxi
Device encryption is excellent while the phone is locked with a passcode. It does nothing at all if the phone is unlocked or has no passcode, which is a large number of phones.
Store less
The cheapest protection available. Data that was never written to the device cannot be recovered from it, and a list that can be refetched in a second does not need to live in a local database forever.
Protect the files you keep
Both platforms allow sensitive files to be marked so they are unreadable until the device has been unlocked, and to be excluded from backups where that is appropriate. Defaults are convenient rather than careful.
Mind the app switcher
The system photographs your screen when the app goes to the background. Sensitive screens need to be masked, and on Android the secure-window flag also blocks screenshots and screen recording.
Clipboard and caches
Copied codes, cached images of documents, downloaded attachments and web view storage all outlive the session. Sensitive copies should expire, and caches should be cleared on sign-out.
Sessions that end
For a higher-risk app, a session that lasts forever is a decision, not an accident. Short sessions, re-authentication for sensitive actions, and a sensible inactivity timeout do more than most cryptography.
Revocation from the server
You need a way to cut off a device without waiting for a token to expire, and the user needs a way to ask for it. Server-side revocation is what turns a lost phone into an inconvenience.
Deletion that is real
Account deletion has to remove data on the server as well as on the device, and both stores now expect an in-app route to it. Half-deleting is worse than not offering it.
Company handsets
Where an enterprise deploys the app to managed devices, policies about backups, screenshots and copying are set centrally. Worth designing with, not against — see enterprise apps.
Ask for Less, and Be Able to Explain What You Took
Privacy on mobile is mostly a design discipline rather than a legal one. Both stores now make you declare your collection publicly, so a short, defensible list is worth more than a comprehensive one.
Minimise the permissions
Every permission you request is a prompt someone can decline, a question a reviewer can ask, and a line in your declaration. Ask for the narrowest version that works, such as approximate location instead of precise, and only for the features that genuinely need it.
Ask in context
Prompting at launch, before anything has been explained, produces refusals that are effectively permanent. Ask at the moment the feature is used, after a sentence saying what it enables, and design the refusal path as carefully as the acceptance one.
Audit the SDKs
Analytics, advertising, crash, chat and support libraries all collect on your behalf and you are the one declaring it. Every dependency is a privacy decision, which is the least glamorous and most reliable argument for keeping the dependency list short.
Declarations on both stores
Apple privacy labels and manifests, Google data safety answers, filled in from what the code and its libraries genuinely do rather than from a marketing description. The submission mechanics are on launch and submission.
Tracking is its own question
Linking a person across apps or companies is treated separately from collecting data to run your own product, and on iOS it requires explicit permission. Most people decline, so a business plan that assumes otherwise needs revisiting early.
A policy that matches reality
Your privacy policy, your store declarations and your code have to agree. When they drift apart it is usually because a library was added without anyone updating the other two, so we check all three at release.
If Minors Can Use It, the Rules Change
This applies whether the app is aimed at children or simply likely to attract them, and both stores ask you to declare which. The consequences reach design, advertising and moderation, not just paperwork.
Declare the audience honestly
Both stores run separate programmes and stricter review for children. Declaring a general audience while designing something obviously aimed at eight-year-olds is a policy problem that tends to be discovered late and resolved badly.
Collect the minimum
Less data, fewer identifiers, no profiling, and a hard look at anything optional. The safest design is one where a child can use the app usefully without an account at all.
No behavioural advertising
Advertising to children is heavily restricted, and networks that personalise by tracking are generally not acceptable. If the plan was ad revenue, that plan needs re-examining before build rather than after.
Anything user-generated
Chat, photos, profiles and comments bring moderation, reporting and blocking obligations that are a product in their own right. This is a scoping conversation with real cost attached.
Consent and age signals
Where parental consent is required you need a mechanism for it and a record that it happened. Age gates should be designed as part of onboarding, not added as a checkbox the week before submission.
Purchases handled carefully
Pressure tactics, confusing currencies and purchase flows that a child can complete without understanding attract scrutiny from both stores. Keep them plain, and keep them behind whatever gate is appropriate.
Specific obligations vary by country and we do not pretend otherwise. We design to a strict, general baseline and tell you plainly where you need your own legal advice for the markets you sell into.
What We Do Not Claim
Security is a field with a lot of confident language in it. Here is where our work ends.
Where This Connects
Launch & Submission
Where the privacy declarations are completed and reviewed against the code.
Learn moreTesting & QA
Permission denial paths, lock-screen behaviour and upgrade cases, tested on real devices.
Learn moreSupport Plans
Dependency updates, certificate renewals and policy changes handled on a retainer.
Learn moreSecurity Questions
Can we put the API key in the app if it is obfuscated?
You can put it there. You cannot keep it secret. An app binary is a file on a device somebody else owns, and it can be unpacked, searched for strings and watched while it runs. Obfuscation raises the effort required from minutes to hours; it does not change the outcome for anyone motivated. So the rule we work to is that a shipped app holds no credential that would matter if it were published on a forum tomorrow. Anything genuinely sensitive stays on a server that the app talks to, the server holds the third-party keys, and the app is issued a short-lived token that belongs to one user and can be revoked.
Is certificate pinning worth doing?
Sometimes, and it is not free. Pinning means the app only trusts specific certificates or keys for your servers, which defeats an attacker who has persuaded a device to trust a certificate it should not. The cost is operational: the day that certificate is replaced, every app version still holding the old pin stops working, and the fix is a store release rather than a server change. If you pin, you plan for it, with backup pins, a renewal calendar owned by a named person, and a way to relax the pin remotely. For a banking or health app it is usually justified. For a content app it often adds more outage risk than it removes attack risk.
Is fingerprint or face unlock enough to secure an account?
It is a good lock on the device, and it is not by itself proof to your server that anyone authenticated. Biometrics done properly do not check a face and then set a flag in your code, because a flag can be flipped. They unlock a key held in the secure hardware of the phone, and that key is what signs or decrypts the thing you actually needed. Two other details matter: there has to be a fallback to the device passcode, because sensors fail and some people cannot use them, and the stored key should be invalidated if the enrolled biometrics change, so adding a new face to the phone does not silently inherit access to your app.
Should the app refuse to run on a rooted or jailbroken phone?
Usually not outright, unless a regulator or a customer contract requires it. Detection is genuinely useful as a signal, but it is a contest you are structurally losing: the tools that modify a device are also the tools that hide from detection, so the person you most want to stop is the one most likely to get through, while false positives block ordinary people with unusual but legitimate setups. The better pattern is to treat a modified device as higher risk rather than as forbidden, raise the sensitivity of server-side checks, restrict the riskiest actions, and keep the real enforcement on the server where the attacker cannot edit it.
What happens to our data if a user loses their phone?
Modern handsets encrypt storage by default, and that protects data well while the device is locked with a passcode. It protects nothing if the device is unlocked or has no passcode at all, which is why sensitive apps should not rely on it alone. The practical measures are to store as little as possible on the device in the first place, keep credentials in the platform keychain rather than in ordinary preference files, mark sensitive files so they cannot be read until the device is first unlocked, exclude them from device backups where that is appropriate, hide sensitive screens in the app switcher, keep sessions short for high-risk apps, and be able to revoke a session from the server so a lost device can be cut off without waiting for anything to expire.
Our app might be used by children. What changes?
Quite a lot, and it starts at scoping rather than at submission. Both stores run separate programmes and stricter rules for apps aimed at or likely to appeal to children, and both ask you to declare your intended audience. In broad terms the expectations are: collect the minimum data needed, no behavioural advertising or tracking for children, careful handling of anything user-generated including moderation and reporting, an age signal appropriate to your audience, parental consent where it is required, and no dark patterns around purchases. Specific obligations differ by country, so we design to the strictest reasonable baseline and tell you plainly where you need your own legal advice.
Have the Security Decisions Made Before the Build
Tell us what the app handles and who uses it. You get back the storage, transport and authentication decisions in writing, with the trade-offs stated rather than buried.