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
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.