# 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

<!-- GUIDANCE: Identify the realistic threat actors and attack vectors for this specific app. Not all threats apply to all apps. -->

| 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:**
1. Auth tokens (access + refresh)
2. User PII (name, email, payment info)
3. API keys and secrets
4. Cached sensitive data

---

## 2. Authentication

### 2.1 Biometric Authentication

<!-- GUIDANCE: Define when biometrics are used and the fallback mechanism. -->

**Implementation:** `{{expo-local-authentication | react-native-biometrics}}`

```ts
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:**

```ts
// 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}}`

```ts
// 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

```ts
// 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

<!-- GUIDANCE: Certificate pinning prevents MITM attacks even with trusted CA certificates. Implement for all critical API calls. -->

**Library:** `{{react-native-ssl-pinning | OkHttp certificate pinner (Android native) | URLSession (iOS native)}}`

```ts
// 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:**
1. Pin BOTH current cert and backup cert simultaneously
2. Deploy app update with new cert added
3. After old cert expires, remove old cert from pins
4. 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

<!-- GUIDANCE: Root/jailbreak detection is defense-in-depth — determined attackers can bypass it. Use it to reduce surface area, not as sole defense. -->

**Library:** `{{expo-device | react-native-jail-monkey | custom}}`

```ts
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

```ts
// 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 | | | |