Mobile App Security: Comprehensive Best Practices for 2026
Mobile app security differs fundamentally from web security because the client device is untrusted territory. Users can jailbreak devices, intercept traffic, decompile binaries, and modify runtime behavior. This guide covers essential security measures that protect your users and business from real attacks.
Secure Storage: Protecting Sensitive Data
// iOS: Keychain Services (hardware-backed)
class SecureStorage {
static func save(key: String, data: Data) throws {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
kSecAttrAccessControl as String: SecAccessControlCreateWithFlags(
nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
.biometryCurrentSet, nil)!
]
SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
guard status == errSecSuccess else { throw KeychainError.saveFailed(status) }
}
}// Android: EncryptedSharedPreferences
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.setUserAuthenticationRequired(true)
.build()
val prefs = EncryptedSharedPreferences.create(
context, "secure_prefs", masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)Mobile App Security: Certificate Pinning
Certificate pinning prevents MITM attacks by verifying the server certificate matches a known good certificate.
// Android: OkHttp certificate pinning
val client = OkHttpClient.Builder()
.certificatePinner(CertificatePinner.Builder()
.add("api.example.com",
"sha256/AAAA...=", // Primary
"sha256/BBBB...=") // Backup
.build())
.build()
// Also use network_security_config.xml for defense in depth
// <network-security-config>
// <domain-config cleartextTrafficPermitted="false">
// <domain includeSubdomains="true">api.example.com</domain>
// <pin-set expiration="2027-01-01">
// <pin digest="SHA-256">AAAA...=</pin>
// </pin-set>
// </domain-config>
// </network-security-config>Code Obfuscation and Tamper Detection
// Runtime integrity checks
object IntegrityChecker {
fun isDeviceCompromised(context: Context): Boolean {
return isRooted() || isDebuggerAttached() ||
isEmulator() || !isSignatureValid(context)
}
private fun isRooted(): Boolean {
val paths = listOf("/system/app/Superuser.apk",
"/system/xbin/su", "/system/bin/su")
return paths.any { File(it).exists() }
}
private fun isDebuggerAttached() = Debug.isDebuggerConnected()
private fun isEmulator(): Boolean =
Build.FINGERPRINT.contains("generic") ||
Build.MODEL.contains("Emulator")
private fun isSignatureValid(context: Context): Boolean {
val expected = "expected_sha256_hash"
val info = context.packageManager.getPackageInfo(
context.packageName, PackageManager.GET_SIGNATURES)
val digest = MessageDigest.getInstance("SHA-256")
.digest(info.signatures[0].toByteArray())
return digest.toHexString() == expected
}
}API Security and Device Attestation
// Android: Play Integrity API
class ApiClient(private val context: Context) {
suspend fun makeRequest(url: String): Response {
val token = IntegrityManager
.createStandardIntegrityManager(context)
.requestIntegrityToken(
StandardIntegrityTokenRequest.builder()
.setRequestHash(hashPayload(url))
.build()
).await()
return httpClient.newCall(Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer ${getAuthToken()}")
.addHeader("X-Integrity-Token", token.token())
.build()
).execute()
}
}OWASP MASVS Checklist
Level 1 (Every App):
- No sensitive data in logs/backups
- TLS for all network traffic
- Secure authentication and sessions
- Secure data storage (Keychain/Keystore)
Level 2 (Banking, Health):
- Certificate pinning
- Biometric authentication
- Device attestation (Play Integrity/App Attest)
- Root/jailbreak detection
- Token rotation
Level R (DRM, Payments):
- Code obfuscation (ProGuard/R8)
- Debugger detection
- Integrity verification
- Emulator detection
- Anti-instrumentation (Frida detection)Key Takeaways
For further reading, refer to the Android developer docs and the Apple developer docs for comprehensive reference material.
Key Takeaways
- Start with a solid foundation and build incrementally based on your requirements
- Test thoroughly in staging before deploying to production environments
- Monitor performance metrics and iterate based on real-world data
- Follow security best practices and keep dependencies up to date
- Document architectural decisions for future team members
Mobile app security requires layered defense because the client device is inherently untrusted. Implement hardware-backed secure storage, certificate pinning, runtime integrity checks, and device attestation. Follow OWASP MASVS as your baseline. Security is an ongoing process that evolves with the threat landscape.
In conclusion, Mobile App Security Practices is an essential topic for modern software development. By applying the patterns and practices covered in this guide, you can build more robust, scalable, and maintainable systems. Start with the fundamentals, iterate on your implementation, and continuously measure results to ensure you are getting the most value from these approaches.