Back to all articles

Mobile App Security Best Practices: Protect User Data in 2025

Mobile app security breaches cost companies an average of $4.35M. With 43% of cyberattacks targeting small businesses, security is non-negotiable. This guide covers essential security practices.

Security Landscape

  • 98% of mobile apps have at least one security flaw
  • 43% of data breaches involve mobile devices
  • Average cost of breach: $4.35 million
  • 60% of users abandon apps after security breach

Data Encryption

Data at Rest

iOS - Keychain:
let query: [String: Any] = [
  kSecClass as String: kSecClassGenericPassword,
  kSecAttrAccount as String: "authToken",
  kSecValueData as String: token.data(using: .utf8)!
]
SecItemAdd(query as CFDictionary, nil)

Android - EncryptedSharedPreferences:
val masterKey = MasterKey.Builder(context)
  .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
  .build()

val prefs = EncryptedSharedPreferences.create(
  context, "secure_prefs", masterKey,
  EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
  EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

Data in Transit

  • Use HTTPS exclusively (TLS 1.3)
  • Implement certificate pinning
  • Validate SSL certificates
  • Use strong cipher suites
  • Avoid insecure protocols (HTTP, FTP)

Authentication Security

Password Best Practices

  • Minimum 8 characters
  • Complexity requirements
  • No dictionary words
  • Salt and hash (bcrypt, Argon2)
  • Never store plaintext

Biometric Authentication

iOS - Face ID/Touch ID:
let context = LAContext()
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
  localizedReason: "Authenticate to access") { success, error in
  if success {
    // Grant access
  }
}

Android - BiometricPrompt:
val biometricPrompt = BiometricPrompt(this, executor, callback)
val promptInfo = BiometricPrompt.PromptInfo.Builder()
  .setTitle("Biometric login")
  .setSubtitle("Log in using fingerprint")
  .setNegativeButtonText("Use password")
  .build()
biometricPrompt.authenticate(promptInfo)

OAuth 2.0 / OIDC

  • Use Authorization Code Flow with PKCE
  • Short-lived access tokens
  • Refresh token rotation
  • Secure token storage
  • Token revocation endpoints

API Security

Secure Communication

Best practices:
✓ API keys in environment variables (never hardcode)
✓ Request signing
✓ Rate limiting (prevent DDoS)
✓ Input validation
✓ Output encoding

Example header:
Authorization: Bearer 
X-API-Key: 
X-Request-ID: 
X-Timestamp: 
X-Signature: 

Certificate Pinning

iOS:
let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
  certificates: ServerTrustPolicy.certificates(),
  validateCertificateChain: true,
  validateHost: true
)

Android:
val certificatePinner = CertificatePinner.Builder()
  .add("api.example.com", "sha256/AAAAAAA...")
  .build()

val client = OkHttpClient.Builder()
  .certificatePinner(certificatePinner)
  .build()

Code Obfuscation

iOS

  • Use Swift (harder to reverse engineer than Objective-C)
  • Enable Bitcode
  • Strip symbols in release
  • Use ProGuard-equivalent tools

Android

ProGuard configuration:
-keep class com.example.api.** { *; }
-keepclassmembers class * {
  @com.google.gson.annotations.SerializedName ;
}
-dontwarn okhttp3.**

R8 (default in Android):
android {
  buildTypes {
    release {
      minifyEnabled true
      shrinkResources true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
    }
  }
}

Secure Storage

What NOT to Store Locally

  • ❌ Passwords (even hashed)
  • ❌ Credit card numbers
  • ❌ API secrets
  • ❌ Private keys
  • ❌ Session tokens (use secure storage)

Secure Storage Options

iOS:

  • Keychain Services
  • Data Protection API
  • Secure Enclave (biometric data)

Android:

  • Android Keystore
  • EncryptedSharedPreferences
  • SQLCipher (encrypted databases)

Session Management

Token Strategy

Access token:
- Short-lived (15 minutes)
- Stored in memory only
- Included in API requests

Refresh token:
- Long-lived (30 days)
- Stored in secure storage
- Used to get new access tokens
- Can be revoked server-side

Logout:
- Clear all tokens
- Revoke on server
- Clear user data
- Reset app state

Input Validation

Client-Side Validation

  • Sanitize all user input
  • Validate email format
  • Check phone numbers
  • Limit input length
  • Prevent SQL injection

Common Vulnerabilities

SQL Injection:
❌ "SELECT * FROM users WHERE id = " + userId
✓ Use prepared statements with parameterized queries

XSS (in WebView):
❌ webView.loadData(userInput)
✓ webView.loadData(sanitize(userInput))

Path Traversal:
❌ File(userInput).read()
✓ Validate and sanitize file paths

Jailbreak/Root Detection

iOS Jailbreak Detection

func isJailbroken() -> Bool {
  // Check for jailbreak files
  let paths = [
    "/Applications/Cydia.app",
    "/usr/sbin/sshd",
    "/bin/bash"
  ]
  for path in paths {
    if FileManager.default.fileExists(atPath: path) {
      return true
    }
  }

  // Check if can write outside sandbox
  let testPath = "/private/test.txt"
  do {
    try "test".write(toFile: testPath, atomically: true, encoding: .utf8)
    try FileManager.default.removeItem(atPath: testPath)
    return true
  } catch {
    return false
  }
}

Android Root Detection

fun isRooted(): Boolean {
  // Check for su binary
  val paths = arrayOf(
    "/system/app/Superuser.apk",
    "/system/xbin/su",
    "/system/bin/su"
  )
  for (path in paths) {
    if (File(path).exists()) return true
  }

  // Check build tags
  val buildTags = Build.TAGS
  if (buildTags != null && buildTags.contains("test-keys")) {
    return true
  }

  return false
}

Secure Logging

What Not to Log

  • ❌ Passwords or PINs
  • ❌ Credit card numbers
  • ❌ API keys or secrets
  • ❌ Session tokens
  • ❌ Personal identifiable information (PII)

Safe Logging

// Bad
print("User logged in: \(email), token: \(token)")

// Good
logger.info("User logged in", metadata: [
  "user_id": userId,
  "timestamp": Date().iso8601
])

// Production
#if DEBUG
  print("Debug: \(sensitiveData)")
#endif

Third-Party Libraries

Security Audit

  • Review library permissions
  • Check for known vulnerabilities
  • Use dependency scanning (Snyk, WhiteSource)
  • Keep libraries updated
  • Remove unused dependencies

SDK Security

  • Verify SDK authenticity
  • Review SDK privacy policy
  • Limit SDK permissions
  • Monitor SDK network activity
  • Use official sources only

Compliance Requirements

GDPR

  • Data encryption
  • Right to deletion
  • Data portability
  • Breach notification (72 hours)
  • Privacy by design

HIPAA (Health Apps)

  • End-to-end encryption
  • Access controls
  • Audit logs
  • Business associate agreements
  • PHI protection

PCI DSS (Payment Apps)

  • Never store CVV
  • Encrypt cardholder data
  • Use tokenization
  • Secure transmission
  • Regular security testing

Security Testing

Penetration Testing

  • Static analysis (SAST)
  • Dynamic analysis (DAST)
  • Manual security review
  • Third-party audit
  • Bug bounty programs

Automated Security Scanning

  • MobSF: Mobile Security Framework
  • OWASP ZAP: Web app scanner
  • Burp Suite: Penetration testing
  • Checkmarx: Static code analysis

Incident Response

Breach Response Plan

  1. Detect: Monitor for anomalies
  2. Contain: Isolate affected systems
  3. Investigate: Determine scope
  4. Notify: Users and authorities
  5. Remediate: Fix vulnerabilities
  6. Review: Post-mortem analysis

Security Checklist

□ All data encrypted (at rest and in transit)
□ HTTPS only (certificate pinning)
□ Secure authentication (OAuth 2.0/biometric)
□ Input validation on all user input
□ Code obfuscation enabled
□ No sensitive data in logs
□ Jailbreak/root detection
□ Third-party libraries audited
□ Secure storage for tokens
□ API rate limiting
□ Regular security testing
□ Incident response plan
□ Compliance requirements met
□ Security training for team

Conclusion

Security is an ongoing process, not a one-time task. Implement defense in depth, stay updated on threats, and prioritize user data protection to build trust and avoid costly breaches.

Need a Support URL for Your App?

Generate a compliant, professional support page in under a minute. Our easy-to-use generator creates everything you need for App Store and Google Play submissions.