| name | apply-mobile-code-hardening |
| description | Use when preparing a mobile app for production release — especially apps handling financial data, DRM content, or anti-cheat systems — to raise the bar against reverse engineering, tampering, and runtime manipulation. |
| source | OWASP Mobile Top 10 2024 M7 (owasp.org/www-project-mobile-top-10/); OWASP MASVS MSTG-RESILIENCE; CWE-693; Google Play Integrity API; Apple DeviceCheck documentation |
| tags | ["security","owasp","mobile","code-hardening","obfuscation","anti-tamper","reverse-engineering","ios"] |
Apply Mobile Code Hardening
Apply code obfuscation, root/jailbreak detection, debug detection, and integrity verification to raise the cost of reverse engineering and runtime manipulation — critical for apps with high-value secrets, DRM, or anti-fraud requirements.
Why This Is Best Practice
Adopted by: OWASP Mobile Top 10 2024 M7 (Insufficient Binary Protections). OWASP MASVS MSTG-RESILIENCE defines the standard for mobile binary protection. Google Play Integrity API and Apple DeviceCheck are platform-provided integrity attestation services. Financial services apps (banking, payment), gaming apps (anti-cheat), and DRM apps (streaming) universally apply these controls — required by PCI DSS v4.0 Requirement 6.3 for payment apps.
Impact: Mobile apps are distributed to untrusted devices — the reverse engineering tooling (jadx for Android, Hopper/Ghidra for iOS, Frida for both) is freely available and capable. Unprotected banking apps have had API keys extracted to build unauthorized clients. Gaming apps without anti-cheat have been reverse-engineered to enable automated bots. DRM content has been extracted from streaming apps. Code hardening raises the cost from minutes to weeks or months.
Why best: Code hardening is an arms race — determined attackers with resources will eventually break any protection. The goal is to raise the cost of attack beyond the attacker's expected return, not to make it impossible. Combined with server-side validation and monitoring, hardening reduces the class of opportunistic attackers effectively.
Sources: OWASP Mobile Top 10 2024 M7; OWASP MASVS MSTG-RESILIENCE; Google Play Integrity API documentation; Apple DeviceCheck documentation; CWE-693
Steps
-
Enable ProGuard/R8 code obfuscation on Android (minimum baseline):
// build.gradle
android {
buildTypes {
release {
minifyEnabled true // enables R8 code shrinking + obfuscation
shrinkResources true // removes unused resources
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}
# proguard-rules.pro — keep only what's required for reflection/serialization
-keep class com.example.api.model.** { *; } # keep data models for JSON parsing
# Everything else: obfuscated by default
-
Use Google Play Integrity API to verify app authenticity at runtime:
val integrityManager = IntegrityManagerFactory.create(context)
suspend fun verifyAppIntegrity(): Boolean {
val nonce = generateNonce()
val request = StandardIntegrityManager.StandardIntegrityTokenRequest.builder()
.setRequestHash(hashOfRequest(nonce))
.build()
val tokenResponse = integrityManager.requestIntegrityToken(request).await()
val token = tokenResponse.token()
return backendApi.verifyIntegrity(token, nonce)
}
-
Detect root (Android) and jailbreak (iOS):
val rootBeer = RootBeer(context)
if (rootBeer.isRooted) {
analytics.log("rooted_device_detected")
showRootedDeviceWarning()
}
() -> {
jailbreakPaths [
,
,
,
,
]
path jailbreakPaths {
.default.fileExists(atPath: path) { }
}
testPath
{
.write(toFile: testPath, atomically: , encoding: .utf8)
.default.removeItem(atPath: testPath)
} { }
}
Rules
- Code hardening is defense-in-depth, not a complete defense — all sensitive operations must still be validated server-side.
- Root/jailbreak detection should log and optionally degrade functionality — avoid outright blocking as it may affect legitimate users with custom ROMs.
- Detection checks must be spread throughout the code, not concentrated in one place — removing a single check should not bypass all protections.
- Obfuscation does not protect secrets hardcoded in the binary — no hardcoded keys, regardless of obfuscation level.
Common Mistakes
- Applying code hardening only to the release build without testing it — obfuscation can break reflection-based code; test before releasing.
- Treating root detection as a security boundary — it reduces attack surface but is bypassable; server-side validation is the authoritative check.
- Hardcoding API keys in the binary and relying on obfuscation to protect them — obfuscated keys are still extractable by a motivated attacker; use certificate pinning and server-side key validation instead.
- One-time integrity check at launch only — move checks to multiple points in the code so patching the launch check doesn't disable all protection.