--- name: mitm-prevention description: Preventing man-in-the-middle attacks on mobile — user CA posture on newer Android and iOS, cleartext traffic policies, and platform configuration. Use when configuring the app's network security baseline. --- # MITM Prevention Baseline ## Instructions Before pinning, get the platform baseline right. Most real-world MITM on mobile comes from misconfigured cleartext or from accepting user-installed CAs. ### 1. Android: Network Security Config Ship an explicit `res/xml/network_security_config.xml` even if you think defaults are fine: ```xml api.example.com ``` Key points: - `cleartextTrafficPermitted="false"` blocks `http://` at the platform layer. - `` only applies to `android:debuggable="true"` builds — perfect for Charles / mitmproxy in dev, impossible to ship enabled. - Do **not** add `` to `base-config`; that is the most common cause of pinned apps being MITMed. Wire it in `AndroidManifest.xml`: ```xml ``` ### 2. iOS: App Transport Security (ATS) Keep ATS on. The minimum acceptable `Info.plist`: ```xml NSAppTransportSecurity NSAllowsArbitraryLoads NSExceptionDomains legacy.partner.example NSIncludesSubdomains NSExceptionMinimumTLSVersionTLSv1.2 NSExceptionAllowsInsecureHTTPLoads ``` Never set `NSAllowsArbitraryLoads=true` globally. App Review increasingly rejects it. ### 3. User-Installed CAs - Android 7+ (API 24): apps do **not** trust user CAs unless the manifest opts in. Good default — leave it. - iOS: user/profile-installed CAs **are** trusted by default. Pinning is the mitigation (see [tls-pinning](../../network/tls-pinning/SKILL.md)). - Neither platform can fully block a rooted / jailbroken device from MITMing your traffic. Layer attestation ([api-abuse-protection](../api-abuse-protection/SKILL.md)). ### 4. Detecting MITM in Production You usually do **not** want to proactively detect MITM in-app; it becomes a cat-and-mouse game. Instead: - Pin. - Log pin failures server-side as a high-severity anomaly metric. - Require attestation on sensitive endpoints. ### 5. WebViews WebViews inherit system trust — they will happily load a proxied MITM site. Controls: - Never load user-controlled URLs in a WebView that has access to a JS bridge. - Disable `setAllowFileAccessFromFileURLs` / `setAllowUniversalAccessFromFileURLs` on Android. - On iOS, prefer `ASWebAuthenticationSession` or `SFSafariViewController` for any third-party auth — they inherit Safari's protections and can't be MITMed by an in-app JS bridge. ### 6. Deep Links / Universal Links A malicious app on Android can claim the same custom scheme as yours. Mitigations: - Prefer **App Links** (Android) and **Universal Links** (iOS), both of which are HTTPS URLs verified by the OS against `/.well-known/assetlinks.json` or `/.well-known/apple-app-site-association`. - Validate any deep-link parameters server-side before acting on them — never trust an `amount` or `to` field just because it arrived via the registered scheme. ### 7. Flutter / RN Specific - Flutter's `dart:io` `HttpClient` respects Android NSC but **not** iOS ATS in every version — verify on your target. Prefer `dart:io` on iOS going through `URLSession` via a native plugin for anything sensitive. - React Native's JS `fetch` goes through OkHttp (Android) / NSURLSession (iOS), so platform config applies. `XMLHttpRequest` for legacy libraries takes the same path. ## Checklist - [ ] `network_security_config.xml` ships with `cleartextTrafficPermitted="false"` and no user CAs in `base-config`. - [ ] `android:usesCleartextTraffic="false"` in the manifest. - [ ] `NSAllowsArbitraryLoads` is `false`; any `NSExceptionDomains` are narrowly scoped. - [ ] Debug / MITM-proxy overrides are gated to debug builds only. - [ ] No WebView exposes `file://` access or a JS bridge to arbitrary URLs. - [ ] Third-party auth uses `SFSafariViewController` / `ASWebAuthenticationSession`, not an in-app WebView. - [ ] App Links / Universal Links are used for any sensitive deep link; parameters are re-validated server-side.