Why app security matters
Mobile app security is the set of practices that keep your app, its data, and its users safe from theft, tampering, and abuse. It is not a feature you add at the end. It is a property of how the app is designed, built, and operated, and it shows up in every layer from the phone in someone's pocket to the database behind your API. When people trust an app with their name, their location, their messages, their health details, or their payment information, they are handing you something you are then responsible for protecting.
The reason this matters so much on mobile in particular is that a phone is a hostile environment in a way a server is not. Your backend runs on hardware you control, behind a firewall you configure. Your mobile app runs on a device you do not own, that may be years out of date, that may be rooted or jailbroken, and that may be connected to a coffee shop network run by someone with bad intentions. Anything you ship to that device can be pulled apart, read, and modified. A determined person can inspect the files your app writes, watch the traffic it sends, and decompile the code to see how it works. So the guiding assumption for the rest of this guide is simple: treat the device as untrusted, and never rely on the client to keep a secret or enforce a rule that truly matters.
The cost of getting this wrong is real and it is rarely just technical. A breach means notifying users, possibly notifying a regulator, absorbing the reputational hit, and often losing the trust that made the app worth using. For a Canadian business handling personal information there are legal obligations under privacy law that we cover later. For any business, a single embarrassing incident can undo years of goodwill. The good news is that most real-world mobile compromises come from a short list of avoidable mistakes, and a team that understands that list can close off the large majority of the risk with disciplined, unglamorous work.
Security also pays for itself in ways that are easy to miss. An app built with clean authentication, encrypted storage, and a well-guarded API is easier to extend, easier to pass an enterprise procurement review, and easier to certify for compliance later. Building it in from the first sprint costs far less than adding it after a scare. If you are still at the planning stage, our guide to building a mobile app from start to finish shows where these decisions fit in the wider process, and this guide zooms in on the security parts.
The diagram above is the mental model to keep for the whole guide. A well-built app is protected by several independent layers, and each layer assumes the one outside it might fail. If someone gets malware onto the device, the app layer still validates input and checks for tampering. If they get past the app, the transport layer still encrypts traffic. If they intercept traffic, the API still checks who is allowed to do what. No single control is trusted to hold on its own. That is what people mean by defense in depth, and it is the difference between an app that fails safely and one that fails completely the first time one assumption breaks.
Common mobile threats
Before getting into defenses it helps to name the attacks. Most mobile compromises fall into a handful of categories, and once you can recognize them you can reason about whether your app is exposed to each one. Here are the ones that come up most often in the apps we review.
Insecure data storage
This is the most common weakness by a wide margin. An app writes sensitive information, a login token, a password, personal details, a cached copy of private data, to somewhere on the device that is not protected. On a rooted or jailbroken phone, or through a device backup, that data can be read straight off the filesystem. The classic mistakes are storing secrets in plain text files, in shared preferences or user defaults without encryption, in a local database with no protection, or in logs. If an attacker gets physical access to a device, or gets malware onto it, unprotected local data is the first thing they take.
Weak authentication
Authentication is how the app proves who a user is, and it fails in predictable ways. Passwords with no strength requirements. Tokens that never expire, so a stolen one works forever. Session identifiers that are easy to guess. Logic that checks credentials on the device instead of the server, which means anyone who can edit the app can walk straight past the check. Multi-factor authentication that is offered but trivial to skip. Each of these lets an attacker become a user they are not, which is often the whole game.
Insecure APIs and backends
Most mobile apps are a thin client over a set of web APIs, and the API is where the valuable data actually lives. A very common and dangerous mistake is trusting the app too much: assuming that because your app only shows a user their own records, the API does not need to check. An attacker does not use your app. They talk to your API directly with their own tools, and if the API returns any record when asked, they will ask for all of them. Broken authorization, where the server does not confirm that the caller is allowed to touch the specific thing they requested, is one of the most damaging bugs in the whole mobile stack.
Reverse engineering
Any app can be decompiled. Both Android and iOS binaries can be pulled apart to reveal a readable version of the logic, the strings, and anything embedded in the build. Attackers do this to find hardcoded secrets like API keys and passwords, to understand how your API works so they can attack it, and to build modified versions of your app that remove restrictions or inject malicious behavior. You cannot stop reverse engineering completely, but you can make it slow and unrewarding, and you can make sure that nothing you ship to the client is a secret worth stealing.
Insecure data transmission
Data moving between the app and your servers crosses networks you do not control. If any of that traffic goes over plain HTTP, or over HTTPS that the app does not validate properly, someone on the same network can read it or change it in flight. This is a man-in-the-middle attack, and public Wi-Fi makes it easy. The fix is well understood, which is to use TLS for every connection and to verify the certificate, but apps still ship with a stray unencrypted endpoint or with certificate validation accidentally disabled during testing and never turned back on.
These five categories cover most of what goes wrong. The chart below shows, very roughly, how often each one shows up in the apps we look at. It is illustrative rather than a formal study, but the shape matches what most security practitioners will tell you: storage and authentication problems are everywhere, and the flashier attacks are rarer than the boring ones.
The OWASP Mobile Top 10
If you want one industry-standard reference for mobile risk, it is the OWASP Mobile Top 10. OWASP is a respected non-profit that publishes freely available security guidance, and its mobile list is a ranked summary of the most important categories of mobile risk, maintained by practitioners. It is the checklist that professional testers reach for, and it is worth knowing even at a high level because it gives you a shared vocabulary with any security team you work with.
Without reproducing the list verbatim, the themes it covers map closely onto the threats above and the sections that follow. It calls out improper credential usage and hardcoded secrets, weak authentication and authorization, insecure communication, inadequate privacy controls, insufficient cryptography, insecure data storage, poor supply-chain and third-party handling, insufficient binary protections against reverse engineering and tampering, security misconfiguration, and inadequate input and output validation. If you read that list and your app has a confident answer for each item, you are in good shape. If any item makes you unsure, that is exactly where to spend your next hour.
The practical way to use it is as a review gate. Before a release, walk the list and ask, for each category, what our app does and whether we have evidence it works. The official OWASP Mobile Top 10 project page is the source to bookmark, and it links out to deeper testing guides for teams that want them. Treat it as the outline for the rest of this guide, because everything below is really an answer to one or more of its categories.
Secure data storage on the device
Since insecure storage is the most common weakness, this is the highest-value place to get right. The core principle is short: store as little sensitive data on the device as you can, and protect what you must keep with the platform's built-in secure storage rather than rolling your own.
Keep less, protect the rest
The safest data is the data you never wrote to the device. Before storing anything, ask whether the app truly needs a local copy. A lot of sensitive caching exists only because it was easy, not because the feature required it. For everything you do need to keep, the platforms give you dedicated secure stores. On iOS that is the Keychain, which on modern devices is backed by hardware in the Secure Enclave. On Android it is the Keystore system, which on many devices is also hardware-backed. These are the correct homes for tokens, keys, and small secrets, because they encrypt the data and tie it to the device in a way plain files do not. Apple documents the approach in its Security framework reference, and Android covers the equivalent in its security best practices.
What not to do
Do not put secrets in plain shared preferences or user defaults, which are just readable files. Do not store passwords or tokens in an unencrypted local database. Do not write sensitive values to logs, which are a surprisingly common leak, because a log line that was handy during development often ships to production and gets collected by crash tools. Do not embed long-lived secrets in the app bundle, because as the reverse engineering section explained, anything in the build can be extracted. And be careful with device backups and cloud sync, since data that is safe on the device can end up in a backup that is protected differently.
Encrypt local databases and files
When you genuinely need a meaningful amount of structured data on the device, use an encrypted database rather than a plain one, with the encryption key held in the Keychain or Keystore rather than in the code. The platforms and common libraries support this well. The point is that even if someone copies the raw database file off the device, it is unreadable without the key, and the key is in hardware-backed storage they cannot easily reach. Our team wires this up as a default on projects that handle personal data rather than treating it as an add-on.
Authentication and session management
Authentication proves who a user is, and session management keeps them logged in safely afterward. Both are places where small mistakes have large consequences, because they are the front door to everything the user can access.
Do the check on the server
The single most important rule is that authentication and authorization decisions happen on the server, never on the device alone. The app can present a login screen and collect a password, but the actual verification, and every later check of whether this user may do this thing, has to come from the backend. Anything decided purely on the client can be bypassed by anyone who edits the app. This sounds obvious, and yet client-side-only checks are one of the most common serious bugs we find.
Handle credentials and tokens well
Never store or transmit passwords in plain text, and never hardcode credentials in the app. Use a proven authentication standard rather than inventing your own; token-based approaches such as OAuth 2.0 with short-lived access tokens and longer-lived refresh tokens are the common pattern for good reasons. Access tokens should expire quickly so a stolen one is useful only briefly. Refresh tokens should be revocable, so that if a device is lost or an account is compromised you can cut off access from the server side. Store all of these in the Keychain or Keystore, not in plain storage.
Sessions, timeouts, and biometrics
Give sessions a sensible lifetime and end them properly on logout, both on the client and on the server, so a token cannot be reused after the user leaves. For apps that handle sensitive data, re-authenticate for sensitive actions and consider a timeout that locks the app after a period of inactivity. Biometric authentication, Face ID and Touch ID on iOS or the BiometricPrompt API on Android, is a strong and user-friendly second factor or app lock, and it keeps the actual secret in secure hardware rather than in your code. Offer multi-factor authentication where the data justifies it, and make the second factor genuinely required rather than a step users can quietly skip.
Securing the API and backend
For most apps the API is where the real prize sits, so it deserves at least as much attention as the app itself. The mental shift that prevents the worst bugs is this: your API is a public service. Even if only your app is supposed to call it, assume anyone can, because anyone can. Every endpoint has to defend itself as if the friendly client in front of it did not exist.
Authenticate and authorize every request
Every request that touches non-public data must prove who is asking and confirm that they are allowed to touch the specific resource they named. Authentication answers who you are; authorization answers whether you may do this. The most damaging API bug in mobile is broken authorization, where the server checks that you are logged in but not that the record you asked for is yours. An attacker changes an identifier in the request from their own to someone else's and the server hands over data that is not theirs. The fix is to check ownership and permissions on the server for every single object, on every request, without exception.
Validate input and limit abuse
Treat everything coming from the app as untrusted and validate it on the server before use, which closes off injection attacks and malformed-data crashes. Apply rate limiting so a single caller cannot hammer an endpoint to brute-force credentials or scrape your whole dataset. Return as little as the client actually needs, since an endpoint that dumps a full user object when the screen shows only a name is leaking data an attacker will happily collect. Log and monitor for unusual patterns so you notice an attack in progress rather than reading about it later.
Keep secrets on the server
Any key or secret that grants real power, a payment provider secret, a database credential, a privileged third-party key, belongs on your backend, never in the app. If the app needs to use a protected service, route the call through your own backend so the powerful secret stays server-side and the app only ever holds a low-privilege, revocable token. This is one of the strongest reasons to have a proper backend rather than letting the app talk to third-party services directly, and it is a core part of how we approach backend development on projects that handle anything sensitive. If you want the wider picture of what a well-built backend does, our services overview lays it out.
Encryption in transit and at rest
Encryption is how you make data unreadable to anyone without the key, and there are two moments that matter: data moving across the network, and data sitting in storage. You need both, and they are handled differently.
In transit
Every connection the app makes should use TLS, which is the S in HTTPS, with no exceptions for any endpoint. Both platforms now push you toward this by default. iOS App Transport Security requires HTTPS unless you deliberately allow otherwise, and recent Android versions block cleartext traffic by default through the Network Security Configuration. Do not relax those defaults for convenience. The common failure is a single analytics or image endpoint left on plain HTTP, which becomes the weak link an attacker listens on. Use modern TLS, keep your libraries current, and make sure certificate validation is never disabled in a shipping build, a shortcut that sometimes gets added during testing and forgotten.
Certificate pinning
Certificate pinning is a stronger form of transport protection where the app is told in advance exactly which certificate or public key to expect from your server, and refuses to connect if it sees anything else. This defends against man-in-the-middle attacks that rely on tricking the device into trusting a fraudulent certificate, including some corporate or malicious intercepting proxies. Pinning is powerful and worth it for apps handling sensitive data, but it needs a rollover plan, because if your certificate changes and the pinned app was not updated to expect the new one, connections break. Done carefully, with a backup pin and a clear renewal process, it meaningfully raises the bar for network attackers.
At rest
Encryption at rest protects data sitting in storage, both on the device and on your backend. On the device, that means the encrypted local storage and hardware-backed keys covered earlier. On the backend, it means encrypting sensitive fields and databases so that a stolen disk or a leaked backup is not a stolen dataset. Use well-established, standard algorithms and libraries rather than writing your own cryptography, which is one of the fastest ways to introduce a subtle, fatal flaw. The rule that professionals repeat is to never roll your own crypto, and it holds: use the vetted primitives the platforms and mature libraries provide, and manage the keys carefully.
Obfuscation, tamper and root or jailbreak detection
The controls so far protect data and access. This section is about protecting the app binary itself from being pulled apart, understood, and modified. These techniques do not make an app unbreakable, and they are not a substitute for the server-side controls above, but they raise the effort and time an attacker needs, and for many apps that is worthwhile.
Code obfuscation
Obfuscation transforms your compiled code so that when someone decompiles it, the result is hard to read. Names become meaningless, structure is muddied, and following the logic takes far longer. On Android the standard tooling for this is R8 and ProGuard, which shrink and rename your code as part of the release build. On iOS the platform offers less out of the box, so teams use third-party tools for sensitive logic. Obfuscation will not stop a determined expert, but it turns a five-minute skim into a long slog, which deters casual attackers and cloners. Pair it with the discipline of keeping no real secret in the client, so that even a fully readable build reveals nothing worth having.
Tamper detection
Tamper detection lets the app notice if its own code or resources have been modified since you signed them, which is how repackaged and trojanized versions of apps get built. Both platforms provide integrity signals you can use. Apple offers DeviceCheck and App Attest, and Google offers the Play Integrity API, which help your backend confirm that requests are coming from a genuine, unmodified build of your app on a genuine device rather than from a tampered copy or a script. Because these checks are verified on the server, they are much harder to defeat than a check that lives only in the app.
Root and jailbreak detection
A rooted or jailbroken device has had its built-in protections removed, which makes the secure storage and sandboxing you rely on less trustworthy. Detecting that state lets your app respond, whether that means warning the user, disabling the most sensitive features, or declining to run at all for a high-security app such as a banking client. Detection is an ongoing cat-and-mouse game and it can be bypassed, so treat it as one signal among many rather than a wall. Combined with server-side integrity checks it forms a reasonable answer to the question of whether you can trust the environment your app is running in.
Third-party SDK and dependency risks
Almost no app is built entirely in-house. You pull in analytics, crash reporting, advertising, payment, mapping, and dozens of open-source libraries, and every one of them runs inside your app with your app's permissions. That is efficient, and it is also a real part of your attack surface, because a weakness or bad behavior in a dependency becomes a weakness in your app.
What can go wrong
A third-party SDK can collect and transmit more user data than you realized, which becomes your privacy problem the moment it is your app doing the collecting. A library can carry a known vulnerability that an attacker targets. A dependency can be abandoned and stop receiving security fixes. In the worst cases, a compromised package or a malicious update can inject harmful code straight into your build through the supply chain. Because these components ship inside your app, users hold you responsible for what they do, so their behavior is your responsibility.
How to manage the risk
Be deliberate about what you include. Prefer well-maintained, widely-used libraries from reputable sources, and question whether each new dependency is worth the surface it adds. Keep everything up to date, since a large share of real-world compromises exploit known issues that a patch had already fixed. Use automated dependency scanning to flag components with known vulnerabilities, and make reviewing those alerts part of the routine rather than a once-a-year panic. Understand what data each SDK collects and sends, disclose it in your privacy policy, and drop anything that overreaches. Pin dependency versions so a build is reproducible and a surprise update cannot silently change what ships. Managing this well is unglamorous, and it prevents a whole class of incidents.
iOS vs Android security features
The two platforms share the same principles but give you different tools, and a good team uses each platform's native strengths rather than forcing one approach onto both. The table below compares the features that come up most in day-to-day building. Neither platform is simply more secure than the other; they make different trade-offs, and both can host a very secure app or a very insecure one depending on how it is built.
| Security feature | iOS | Android |
|---|---|---|
| Secure key and secret storage | Keychain, backed by the Secure Enclave on supported devices | Android Keystore, hardware-backed on many devices |
| App sandboxing | Strong, each app isolated by default | Strong, each app runs as its own user with its own data directory |
| Biometric authentication | Face ID and Touch ID via LocalAuthentication | Fingerprint and face via the BiometricPrompt API |
| Default transport security | App Transport Security enforces HTTPS by default | Network Security Config, cleartext blocked by default on recent versions |
| Code protection | Platform checks plus third-party obfuscation for sensitive logic | R8 and ProGuard for shrinking and name obfuscation |
| Sideloading and app sources | Locked to the App Store for most users, which narrows the attack surface | Sideloading is possible, so tampered builds are easier to distribute |
| Update reach | New OS versions reach most devices quickly | Fragmented, older versions stay in use for longer |
| Integrity checks | DeviceCheck and App Attest | Play Integrity API |
A few points are worth drawing out. iOS narrows the attack surface by keeping most users on the App Store and pushing OS updates out quickly, so a larger share of devices run recent, patched software. Android is more open, which is part of its appeal, but sideloading makes it easier for tampered copies of an app to circulate, and version fragmentation means you will support older releases with weaker defaults for longer. In practice this means Android apps benefit even more from server-side integrity checks and careful minimum-version choices, while iOS apps still need every one of the storage, transport, and API controls because platform sandboxing protects the device, not your data on your server.
Privacy and compliance (PIPEDA, GDPR, HIPAA)
Security and privacy overlap but are not the same. Security is about protecting data from attackers. Privacy is about collecting and using personal information responsibly and lawfully. If your app touches personal data, and almost all do, you have legal obligations, and the specifics depend on who your users are and what kind of data you handle. This is general guidance rather than legal advice, and for anything high-stakes you should confirm the details with a qualified professional.
PIPEDA in Canada
For Canadian businesses the baseline federal law is PIPEDA, the Personal Information Protection and Electronic Documents Act, which governs how private-sector organizations collect, use, and disclose personal information in the course of commercial activity. Its themes are practical and map onto good product habits: get meaningful consent before collecting personal information, collect only what you actually need for a stated purpose, tell people what you are doing with their data in a clear privacy policy, protect that data with appropriate safeguards, let users access and correct their information, and keep it only as long as you need it. Some provinces have their own comparable laws. Building consent, data minimization, and a readable privacy policy into the app from the start is far easier than retrofitting them.
GDPR and users in Europe
If your app has users in the European Union, the GDPR very likely applies to you regardless of where your company sits. It sets a high bar: a clear lawful basis for processing, explicit and specific consent where consent is the basis, strong user rights including access and deletion, breach notification within a tight window, and real consequences for getting it wrong. Even if you are not targeting Europe today, designing to GDPR-style principles is a sound default because it tends to satisfy most other regimes as well.
HIPAA and health data
If your app handles health information for users in the United States, HIPAA may apply, and it brings strict requirements for how protected health information is stored, transmitted, and accessed, along with the need for agreements with the partners who process that data on your behalf. Health, financial, and children's data are all higher-sensitivity categories that carry extra rules, so if your app is in one of those areas, treat compliance as a first-class requirement rather than a detail to sort out later. The common thread across all of these regimes is the same: collect less, protect what you keep, be honest about what you do, and give users control. An app built that way is both easier to secure and easier to certify. Our team factors these obligations into scope from the beginning, which is much cheaper than discovering them during a procurement review.
Security testing: static, dynamic and pen testing
You cannot know an app is secure by hoping. Testing is how assumptions get checked against reality, and there are three complementary approaches. Used together they cover far more than any one alone, and they should run throughout development rather than once at the end.
Static analysis
Static application security testing examines your source code and configuration without running it, looking for known-bad patterns: hardcoded secrets, weak cryptography, disabled certificate checks, dangerous permissions, and common coding flaws. It is fast, it runs automatically in your build pipeline, and it catches a lot of issues early when they are cheap to fix. It also produces false positives, so someone has to triage the findings, but as a first line it earns its place. Wiring static analysis into continuous integration so every change is scanned is one of the highest-return habits a team can adopt.
Dynamic analysis
Dynamic application security testing exercises the app while it runs, watching real behavior: what it writes to storage, what it sends over the network, how it responds to unexpected input. This is where you catch problems that only appear at runtime, such as a token quietly written to a log, an endpoint that skips validation, or traffic going out unencrypted. It complements static analysis, which cannot see runtime behavior, and it is closer to how an actual attacker probes an app.
Penetration testing
Penetration testing puts a skilled human in the attacker's seat to actively try to break the app and its backend, chaining together the kinds of weaknesses the automated tools flag individually. A good pen test finds the business-logic flaws and authorization gaps that scanners miss, because those require understanding what the app is supposed to do and then finding where it fails to enforce it. For an app handling sensitive data, an independent penetration test before launch, and periodically afterward, is money well spent, and many enterprise customers will require evidence of one before they will buy. The OWASP Mobile Top 10 from earlier is the usual framework a tester works against, so building to that list makes the eventual test go smoothly.
Make it continuous
The teams that stay secure do not treat testing as a gate at the very end. They run static analysis on every commit, exercise the app dynamically as part of their QA, and schedule human penetration tests around major releases. Security is a moving target, because new vulnerabilities in your dependencies and platforms appear after you ship, so testing and patching are an ongoing operating cost, not a one-time project. If you would rather have a team that builds this in from the first sprint, that is exactly how we work, and it is worth reading our guide on how to hire an app development company for what to look for.
A practical mobile app security checklist
Use this as a run-through before you ship and again at each major release. It is organized by the areas covered above, and it is deliberately practical. If your app can answer each item with a confident yes, you have closed off the large majority of real-world risk.
- Data storage. Store as little sensitive data on the device as possible. Keep secrets and tokens in the Keychain or Keystore, encrypt local databases, and keep sensitive values out of logs and unprotected backups.
- Authentication. Verify credentials and permissions on the server, never on the client alone. Use a standard token-based scheme with short-lived, revocable tokens, and offer biometrics and multi-factor authentication where the data justifies it.
- Session management. Expire sessions sensibly, end them on logout on both client and server, and lock the app after inactivity for sensitive use cases.
- API and backend. Authenticate and authorize every request, check object ownership on every call, validate all input server-side, apply rate limiting, and return only the data the client needs.
- Secrets. Keep powerful keys and credentials on the backend. Never hardcode secrets in the app, and route privileged calls through your own server.
- Encryption in transit. Use TLS for every connection with no cleartext exceptions, keep certificate validation enabled in production, and consider certificate pinning with a rollover plan.
- Encryption at rest. Encrypt sensitive data on both the device and the backend using standard, vetted libraries. Never write your own cryptography.
- Hardening. Obfuscate release builds, use server-verified integrity checks such as App Attest or the Play Integrity API, and add root or jailbreak detection for high-sensitivity apps.
- Third-party code. Vet dependencies, keep them patched, scan for known vulnerabilities automatically, pin versions, and understand what data each SDK collects.
- Privacy and compliance. Collect only what you need, get meaningful consent, publish a clear privacy policy, and meet the obligations of PIPEDA, GDPR, or HIPAA as they apply to your users and data.
- Testing. Run static analysis on every change, exercise the app dynamically in QA, and commission an independent penetration test before launch and periodically after.
- Operations. Monitor for unusual activity, have a plan to revoke access and push fixes quickly, and keep platforms and libraries current after launch.
Where this fits
Security is not a phase you finish; it is a standard you hold across the life of the app. The reassuring part is that the fundamentals on this list, done consistently, stop the large majority of real attacks, because most compromises exploit the boring, avoidable gaps rather than exotic techniques. Get the basics right and keep them right, and you are ahead of most of the field. If you want to see how engagements are scoped, our pricing page explains our approach, and when you are ready you can get in touch for a free quote. You own your code, and we build it to be defended from the first line.
Start with the checklist, fix the biggest gaps first, test what you changed, and keep the discipline going after launch. Careful, unglamorous work on the fundamentals protects your users and your business better than any single clever trick, and it is what separates an app people can trust from one that becomes a headline.