Mobile Security

Mobile Security 
 
 Project: {{PROJECT_NAME}}
 Version: {{VERSION}}
 Date: {{DATE}}
 Author: {{AUTHOR}}
 Status: Draft | In Review | Approved
 Reviewers: {{REVIEWERS}} 
 
 Document History 
 
 
 
 Version 
 Date 
 Author 
 Changes 
 
 
 
 
 0.1 
 {{DATE}} 
 {{AUTHOR}} 
 Initial draft 
 
 
 
 
 1. Mobile Threat Model 

 
 
 
 Threat Actor 
 Goal 
 Attack Vector 
 Likelihood 
 Impact 
 Mitigation 
 
 
 
 
 Malicious app on device 
 Steal auth tokens 
 Shared storage access 
 Medium 
 High 
 Secure storage (Keychain/Keystore) 
 
 
 Network interceptor (MITM) 
 Intercept API calls 
 Rogue WiFi, proxy 
 Medium 
 High 
 Certificate pinning 
 
 
 Reverse engineer 
 Extract API keys, business logic 
 APK/IPA decompilation 
 Medium 
 Medium 
 Code obfuscation, no hardcoded secrets 
 
 
 Stolen/lost device 
 Access user data 
 Physical access 
 High 
 High 
 Biometric lock, data encryption, remote wipe 
 
 
 Rooted/jailbroken device 
 Bypass controls 
 OS privilege escalation 
 Low 
 High 
 Root/jailbreak detection 
 
 
 Malicious insider 
 Access user data 
 Source code access 
 Low 
 High 
 Secrets in vault, no PII in logs 
 
 
 
 Assets to protect: 
 
 Auth tokens (access + refresh) 
 User PII (name, email, payment info) 
 API keys and secrets 
 Cached sensitive data 
 
 
 2. Authentication 
 2.1 Biometric Authentication 

 Implementation: {{expo-local-authentication | react-native-biometrics}} 
 import * as LocalAuthentication from 'expo-local-authentication';

export async function authenticateWithBiometrics(): Promise<boolean> {
 const hasHardware = await LocalAuthentication.hasHardwareAsync();
 const isEnrolled = await LocalAuthentication.isEnrolledAsync();

 if (!hasHardware || !isEnrolled) {
 return promptPINFallback();
 }

 const result = await LocalAuthentication.authenticateAsync({
 promptMessage: 'Verify your identity',
 fallbackLabel: 'Use PIN',
 cancelLabel: 'Cancel',
 disableDeviceFallback: false,
 });

 return result.success;
}
 
 Use cases for biometric auth: 
 
 App unlock after backgrounding > {{5 minutes}} 
 View sensitive data (payment info, full account number) 
 Confirm high-value transactions (amount > {{$100}} ) 
 Change security settings 
 
 Fallback: PIN code → {{expo-secure-store}} stored hash (bcrypt, not reversible) 
 
 2.2 Session Management 
 
 
 
 Property 
 Value 
 
 
 
 
 Access token lifetime 
 {{15 minutes}} 
 
 
 Refresh token lifetime 
 {{30 days}} 
 
 
 Refresh token rotation 
 Yes — single use, new token issued on use 
 
 
 Session timeout (background) 
 App lock after {{5 minutes}} inactive 
 
 
 Max concurrent sessions 
 {{3 devices}} 
 
 
 Force logout triggers 
 Password change, suspicious activity, admin revocation 
 
 
 
 Token storage: 
 // CORRECT — encrypted secure storage
await SecureStore.setItemAsync('access_token', token, {
 keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
});

// WRONG — never use AsyncStorage or MMKV for tokens
// await AsyncStorage.setItem('access_token', token); // DO NOT USE
 
 
 2.3 Token Storage (Secure Enclave) 
 
 
 
 Platform 
 Mechanism 
 Access Level 
 
 
 
 
 iOS 
 Keychain Services 
 kSecAttrAccessibleWhenUnlockedThisDeviceOnly 
 
 
 Android 
 Android Keystore 
 BIOMETRIC_STRONG or DEVICE_CREDENTIAL 
 
 
 
 Cannot be backed up: Both mechanisms are device-bound — tokens do not transfer to new devices. 
 
 3. Data Protection 
 3.1 Secure Storage Policy 
 
 
 
 Data Type 
 Allowed Storage 
 Forbidden Storage 
 
 
 
 
 Access token 
 Keychain/Keystore 
 AsyncStorage, MMKV, SQLite 
 
 
 Refresh token 
 Keychain/Keystore 
 AsyncStorage, MMKV 
 
 
 Encryption key 
 Keychain/Keystore 
 Any other storage 
 
 
 User PII 
 SQLite (encrypted) 
 AsyncStorage 
 
 
 Non-sensitive prefs 
 AsyncStorage / MMKV 
 — 
 
 
 
 
 3.2 Data Encryption at Rest 
 Database encryption: {{SQLCipher for SQLite | Realm Encryption}} 
 // SQLCipher initialization with key from Keystore
const encryptionKey = await SecureStore.getItemAsync('db_encryption_key');
const db = await SQLite.openDatabaseAsync('app.db', {
 key: encryptionKey,
});
 
 Key generation: On first launch, generate 256-bit random key, store in Keychain/Keystore. 
 Encrypted fields (beyond DB encryption): 
 
 
 
 Field 
 Encryption 
 Key Source 
 
 
 
 
 Payment card (last 4 only stored) 
 N/A — tokenized 
 Stripe/Braintree 
 
 
 SSN / national ID 
 AES-256-GCM 
 Keychain/Keystore 
 
 
 Private messages 
 End-to-end (Signal protocol) 
 Derived keys 
 
 
 
 
 3.3 Sensitive Data in Memory 
 
 
 
 Rule 
 Implementation 
 
 
 
 
 Clear passwords after use 
 Overwrite string variable, trigger GC 
 
 
 No sensitive data in logs 
 Custom logger strips PII fields 
 
 
 No sensitive data in crash reports 
 Sentry beforeSend hook scrubs payload 
 
 
 No sensitive data in analytics 
 Map user ID → hashed ID before sending 
 
 
 
 
 3.4 Screenshot Prevention 
 // iOS — prevent screenshots programmatically
// (Note: React Native does NOT expose this API — native module required)

// Android — prevent screenshots and screen recording
import { Platform } from 'react-native';
import { preventScreenCapture, allowScreenCapture } from 'expo-screen-capture';

useEffect(() => {
 if (Platform.OS === 'android') {
 preventScreenCapture();
 }
 return () => allowScreenCapture();
}, []);
 
 Screens requiring screenshot prevention: 
 
 Payment / card details screen 
 Account balance screen 
 Personal document viewer 
 {{OTHER_SENSITIVE_SCREEN}} 
 
 
 3.5 Clipboard Protection 
 
 Password fields: secureTextEntry={true} — disables clipboard by default on iOS 
 Sensitive data programmatically copied: clear clipboard after {{60 seconds}} 
 Custom clipboard hook: useSensitiveCopy(value, clearAfterMs: 60000) 
 
 
 4. Network Security 
 4.1 Certificate Pinning 

 Library: {{react-native-ssl-pinning | OkHttp certificate pinner (Android native) | URLSession (iOS native)}} 
 // Using react-native-ssl-pinning
const response = await fetch('https://api.domain.com/endpoint', {
 method: 'POST',
 pkPinning: true,
 sslPinning: {
 certs: ['api_cert_sha256_fingerprint'],
 },
 headers: { /* ... */ },
 body: JSON.stringify(payload),
});
 
 Pinned endpoints: 
 
 api.{{domain.com}} — primary API 
 auth.{{domain.com}} — authentication 
 
 Certificate rotation process: 
 
 Pin BOTH current cert and backup cert simultaneously 
 Deploy app update with new cert added 
 After old cert expires, remove old cert from pins 
 Test rotation in staging first 
 
 Handling pin failures: 
 
 Log as security event to backend 
 Show user-facing error: "Secure connection failed" 
 Do NOT fall back to unpinned connection 
 
 
 4.2 SSL/TLS Configuration 
 
 
 
 Requirement 
 Value 
 
 
 
 
 Minimum TLS version 
 TLS 1.2 
 
 
 Preferred TLS version 
 TLS 1.3 
 
 
 HTTP allowed 
 No (ATS enforced on iOS, enforce on Android) 
 
 
 Cipher suites 
 Forward-secrecy only (ECDHE, DHE) 
 
 
 
 
 4.3 Network Request Encryption 
 
 All requests over HTTPS (enforced via ATS + Android network security config) 
 Sensitive payloads encrypted at application layer (in addition to TLS): {{Yes/No}} 
 Request signing implemented (HMAC): {{Yes/No}} 
 
 
 5. Application Security 
 5.1 Code Obfuscation 
 
 
 
 Platform 
 Tool 
 Status 
 
 
 
 
 Android 
 ProGuard / R8 (enabled by default in release) 
 {{Done/TODO}} 
 
 
 iOS 
 Bitcode + Swift compiler optimizations 
 {{Done/TODO}} 
 
 
 JavaScript 
 Hermes bytecode compilation 
 {{Done/TODO}} 
 
 
 JavaScript (extra) 
 {{metro-react-native-babel-preset obfuscation}} 
 {{Done/TODO}} 
 
 
 
 ProGuard rules: android/app/proguard-rules.pro 
 TODO: Review ProGuard rules to ensure no over-stripping of reflection-dependent code. 
 
 5.2 Root / Jailbreak Detection 

 Library: {{expo-device | react-native-jail-monkey | custom}} 
 import JailMonkey from 'jail-monkey';

export function checkDeviceIntegrity(): SecurityResult {
 const isJailbroken = JailMonkey.isJailBroken();
 const isDebuggedBuild = JailMonkey.isDebuggedMode();
 const onExternalStorage = JailMonkey.isOnExternalStorage(); // Android

 return {
 compromised: isJailbroken || isDebuggedBuild,
 reason: isJailbroken ? 'jailbroken' : isDebuggedBuild ? 'debug' : 'clean',
 };
}
 
 Response to compromised device: 
 
 {{Warn user and allow use with reduced functionality | Block access entirely | Log silently}} 
 Justification: {{Explain decision}} 
 
 
 5.3 Tamper Detection 
 
 App bundle signature verification on launch 
 Resource hash verification for critical assets 
 Backend validates app version — block known compromised versions 
 
 
 5.4 Debug Detection 
 // Detect if app is running under debugger in production
if (__DEV__ === false && detectDebugger()) {
 logSecurityEvent('debugger_attached');
 terminateSession();
}
 
 Production builds must have: 
 
 __DEV__ mode disabled 
 Console.log stripped (Babel plugin: transform-remove-console ) 
 Flipper disabled 
 Source maps NOT bundled with the app binary (upload to Sentry separately) 
 
 
 5.5 Reverse Engineering Prevention 
 
 
 
 Measure 
 Implementation 
 
 
 
 
 No hardcoded secrets 
 All secrets fetched from vault at runtime or injected via CI 
 
 
 No plain API keys in bundle 
 Obfuscated + fetched from secure config endpoint 
 
 
 Sensitive logic on server 
 Business logic requiring security stays backend-side 
 
 
 Binary protection 
 ProGuard / R8 (Android), Bitcode stripping (iOS) 
 
 
 
 TODO: Run MobSF static analysis before each major release and review findings. 
 
 6. OWASP Mobile Top 10 Checklist 
 
 
 
 # 
 Risk 
 Status 
 Notes 
 
 
 
 
 M1 
 Improper Credential Usage 
 {{Pass/Fail/N/A}} 
 Tokens in Keychain, no hardcoded creds 
 
 
 M2 
 Inadequate Supply Chain Security 
 {{Pass/Fail}} 
 Dependency audit npm audit 
 
 
 M3 
 Insecure Authentication/Authorization 
 {{Pass/Fail}} 
 JWT validated server-side 
 
 
 M4 
 Insufficient Input/Output Validation 
 {{Pass/Fail}} 
 Zod validation on all inputs 
 
 
 M5 
 Insecure Communication 
 {{Pass/Fail}} 
 TLS + cert pinning 
 
 
 M6 
 Inadequate Privacy Controls 
 {{Pass/Fail}} 
 Data minimization, GDPR 
 
 
 M7 
 Insufficient Binary Protections 
 {{Pass/Fail}} 
 Obfuscation, no debug build in prod 
 
 
 M8 
 Security Misconfiguration 
 {{Pass/Fail}} 
 No dev configs in prod build 
 
 
 M9 
 Insecure Data Storage 
 {{Pass/Fail}} 
 Keychain/Keystore + encrypted DB 
 
 
 M10 
 Insufficient Cryptography 
 {{Pass/Fail}} 
 AES-256, SHA-256, no MD5/SHA-1 
 
 
 
 
 7. Security Testing Tools 
 
 
 
 Tool 
 Type 
 When 
 Output 
 
 
 
 
 MobSF (Mobile Security Framework) 
 Static analysis 
 Pre-release 
 Risk report 
 
 
 Frida 
 Dynamic analysis 
 Penetration test 
 Runtime behavior 
 
 
 Objection 
 Runtime analysis 
 Penetration test 
 Bypass checks 
 
 
 Burp Suite 
 Network proxy 
 Penetration test 
 API vulnerabilities 
 
 
 OWASP ZAP 
 Automated scan 
 CI/CD 
 Vulnerability report 
 
 
 npm audit / yarn audit 
 Dependency scan 
 Every PR 
 CVE report 
 
 
 
 Penetration test cadence: {{Annual | Before each major release | Quarterly}} 
 Last pentest date: {{DATE}} 
 Next pentest date: {{DATE}} 
 
 8. Compliance Requirements 
 
 
 
 Requirement 
 Applicable 
 Notes 
 
 
 
 
 GDPR (EU users) 
 {{Yes/No}} 
 User data deletion, export endpoints 
 
 
 CCPA (California users) 
 {{Yes/No}} 
 Do Not Sell option 
 
 
 COPPA (under 13) 
 {{Yes/No}} 
 Parental consent flow 
 
 
 PCI DSS (payment data) 
 {{Yes/No}} 
 Use PCI-compliant SDK (Stripe/Braintree) — never store card data 
 
 
 App Store privacy label 
 Yes 
 App Store Connect privacy questionnaire 
 
 
 Play Store data safety 
 Yes 
 Google Play Console data safety form 
 
 
 HIPAA (health data) 
 {{Yes/No}} 
 BAA with vendors, encryption at rest+transit 
 
 
 
 
 Approval 
 
 
 
 Role 
 Name 
 Date 
 Signature 
 
 
 
 
 Author 
 
 
 
 
 
 Mobile Lead 
 
 
 
 
 
 Security Lead 
 
 
 
 
 
 Legal