ESC
Type to search guides, tutorials, and reference documentation.
Verified by Garnet Grid

Mobile App Security

Secure mobile applications against common attack vectors. Covers certificate pinning, secure storage, biometric authentication, code obfuscation, anti-tampering, and the patterns that protect sensitive data on devices you don't control.

Mobile applications run on devices you do not control. Unlike servers behind firewalls, mobile apps can be decompiled, debugged, intercepted, and modified by anyone with a $50 Android phone and free tools. Mobile security is not about making attacks impossible — it is about making them expensive enough that attackers choose easier targets.


Threat Model

Mobile App Attack Surface:

Network Layer:
  ☐ Man-in-the-middle (intercept API traffic)
  ☐ SSL stripping (downgrade HTTPS to HTTP)
  ☐ DNS spoofing (redirect to malicious server)
  
Device Storage:
  ☐ Unencrypted local databases
  ☐ Tokens in SharedPreferences/UserDefaults (plaintext)
  ☐ Sensitive data in logs or screenshots
  ☐ Backup extraction (adb backup, iTunes backup)

Binary Analysis:
  ☐ Decompilation (jadx, Hopper)
  ☐ API keys hardcoded in binary
  ☐ Business logic reverse engineering
  ☐ Tampering (modify app, resign, distribute)

Runtime:
  ☐ Debugger attachment (Frida, LLDB)
  ☐ Method swizzling/hooking
  ☐ Jailbreak/root detection bypass
  ☐ Clipboard interception

Certificate Pinning

// iOS: Certificate pinning with URLSession
class PinnedSessionDelegate: NSObject, URLSessionDelegate {
    
    // SHA256 hash of your server's certificate public key
    let pinnedPublicKeyHash = "sha256/YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="
    
    func urlSession(_ session: URLSession, 
                    didReceive challenge: URLAuthenticationChallenge,
                    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        
        guard let serverTrust = challenge.protectionSpace.serverTrust,
              let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }
        
        // Extract public key and hash it
        let publicKey = SecCertificateCopyKey(certificate)
        let publicKeyHash = sha256Hash(of: publicKey)
        
        if publicKeyHash == pinnedPublicKeyHash {
            completionHandler(.useCredential, URLCredential(trust: serverTrust))
        } else {
            // Pin mismatch — possible MITM attack
            completionHandler(.cancelAuthenticationChallenge, nil)
            reportPinningFailure()
        }
    }
}

Secure Storage

// Android: Secure storage with EncryptedSharedPreferences
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKeys

class SecureStorage(context: Context) {
    
    private val masterKey = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
    
    private val securePrefs = EncryptedSharedPreferences.create(
        "secure_prefs",
        masterKey,
        context,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )
    
    fun saveToken(token: String) {
        securePrefs.edit().putString("auth_token", token).apply()
    }
    
    fun getToken(): String? {
        return securePrefs.getString("auth_token", null)
    }
    
    // NEVER do this:
    // SharedPreferences.edit().putString("token", token)  // Plaintext!
    // File("token.txt").writeText(token)                   // Plaintext file!
    // Log.d("Auth", "Token: $token")                       // In logs!
}

Anti-Patterns

Anti-PatternConsequenceFix
Hardcoded API keys in binaryExtracted in minutes with jadxServer-side key management, short-lived tokens
Plaintext token storageToken stolen from device backupEncryptedSharedPreferences / Keychain
No certificate pinningTraffic intercepted by proxy toolsPin server certificate public key
Sensitive data in logsVisible in logcat/ConsoleStrip logs in release builds
Trust jailbreak detection aloneBypassed in minutes with FridaDefense in depth, not single detection

Mobile security is defense in depth. No single protection is unbreakable — but layering certificate pinning, secure storage, obfuscation, and anti-tampering makes attacks expensive enough to deter most adversaries.

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →