Information Security
Mobile Application Security
HackerOne Mobile Security Report 2023: mobile applications receive 37% more high-severity bug reports than web applications. The reason: developers assume that server-side protection handles everything. But mobile apps run on devices controlled by the user - the attacker has physical access, can jailbreak, can intercept traffic, can decompile the binary. The threat model for mobile is fundamentally different from web.
- **Uber 2019**: tokens stored in UserDefaults without encryption - a bug bounty report demonstrated reading them from a jailbroken iPhone in 2 minutes.
- **Banking apps (OWASP research 2022)**: 40% of banking applications did not use certificate pinning - traffic was interceptable via Burp Suite with a custom CA.
- **Revolut bug bounty**: $25,000 for discovering an API endpoint without authorization in the mobile application - access to other users' transaction data.
Certificate Pinning: Trusting a Specific Certificate
TLS protects traffic but trusts any CA from the system store - there are 100+ of them. An attacker with device access (corporate MDM, rooted device) can install a custom CA and intercept encrypted traffic. Certificate pinning removes this trust: the app accepts only a specific certificate or public key, rejecting all others including valid CA-signed certs.
Always pin two certificates: the current and a backup. If the server certificate changes (planned rotation or incident), the app stops working until an update is shipped. The backup pin should be the next certificate in the chain (intermediate CA) or the upcoming leaf cert. Android Network Security Config (API 24+) provides declarative pinning without code: res/xml/network_security_config.xml.
Certificate pinning is configured. A security researcher with a rooted Android installs their own CA. Can pinning be bypassed?
Root Detection: Raising the Cost of Analysis
Root/jailbreak opens a device to application analysis: Frida for hooking, Objection for bypass, r2frida for memory analysis. Banking, payment, and DRM apps use root detection as an additional defense layer. Detection does not make bypass impossible - it raises the cost and required skill level.
SafetyNet / Play Integrity API (Google): server-side attestation. The device sends a Google-signed certificate proving it is unrooted and not emulated. Harder to bypass than client-side checks because the verification happens on Google's servers. The app sends the attestation token to the backend, which validates it with Google's API before granting elevated permissions.
Root detection fires. The app immediately crashes (force closes). Is this the correct approach?
Secure Storage: Protecting Tokens and Keys
OWASP Mobile Top 10 #2: Insecure Data Storage. SharedPreferences and UserDefaults store data as plain XML. SQLite without encryption is readable as a plain file. On a rooted or jailbroken device, all of these are accessible without any bypass. Tokens and keys must be stored in the platform secure enclave: Keychain on iOS, Keystore on Android.
Hardcoded secrets in code (OWASP Mobile Top 10 #6): after decompiling an APK or IPA, attackers can see API keys, encryption keys, and internal API URLs. The solution: retrieve secrets from a remote config endpoint at app startup, protected by certificate pinning. Never hardcode production API keys, private keys, or internal service endpoints in mobile app binaries.
An access token is stored in UserDefaults on iOS. The device is jailbroken. What happens?
Obfuscation: Raising the Cost of Reverse Engineering
APKs and IPAs can be decompiled: jadx for Android, class-dump for iOS. Without obfuscation, attackers see class names, method names, strings, API endpoints, and business logic. Obfuscation does not prevent reverse engineering - it raises the time and skill cost. It is one layer in a defense-in-depth strategy.
R8/ProGuard obfuscates identifiers but not string values by default. Hardcoded API keys remain visible as plain strings even after obfuscation. String encryption requires additional tools (DexGuard, StringFog). For iOS, SwiftShield obfuscates Swift symbol names. The most effective protection combines obfuscation with runtime attestation (Play Integrity API) and server-side validation.
Obfuscation is enabled. An attacker runs the app through Frida. Does obfuscation help?
Key Ideas
- **Certificate pinning**: the app accepts only a specific public key hash. Blocks MITM even with a trusted CA. Bypassable on rooted devices via Frida - combine with root detection.
- **Root detection**: raises the cost of analysis via multiple checks. Respond with degraded mode (not crash) to disable sensitive features. Play Integrity API provides server-validated attestation.
- **Secure storage**: tokens in Keychain (iOS) or Keystore (Android), not UserDefaults/SharedPreferences. Never hardcode secrets - retrieve from remote config at startup.
- **Obfuscation**: protects against static analysis (jadx, class-dump). Does not prevent runtime hooking via Frida. Strings are not obfuscated by default - require separate string encryption.
Related Topics
Mobile security builds on authentication fundamentals and connects to backend API security:
- Authentication and Authorization — Mobile authentication: biometrics combined with Keychain-stored tokens and certificate pinning.
- Data Encryption: At Rest and In Transit — Keychain and Keystore use AES and RSA primitives for local key storage and encryption.
- API Security — Mobile backend APIs have the same requirements for authentication, rate limiting, and input validation.
Вопросы для размышления
- A banking app pins certificates. The security team plans to rotate the server certificate in 30 days. Design the rotation process to avoid a production outage.
- A competitor's iOS app is copying your business logic. What combination of protections would you implement to raise the reverse engineering cost without impacting legitimate users?
- An attacker has physical access to a lost employee phone. It is not jailbroken. What data is at risk and what policies would minimize the exposure?