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
- Detect: Monitor for anomalies
- Contain: Isolate affected systems
- Investigate: Determine scope
- Notify: Users and authorities
- Remediate: Fix vulnerabilities
- 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.