見出し、例、コード、表、リンク、参照画像を含む原文を表示しています。
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 version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system"/>
<!-- user CAs are NOT trusted by default from Android 7+ -->
</trust-anchors>
</base-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">api.example.com</domain>
</domain-config>
<debug-overrides>
<trust-anchors>
<certificates src="user"/>
</trust-anchors>
</debug-overrides>
</network-security-config>Key points:
cleartextTrafficPermitted="false"blockshttp://at the platform layer.<debug-overrides>only applies toandroid:debuggable="true"builds — perfect for Charles / mitmproxy in dev, impossible to ship enabled.- Do not add
<certificates src="user"/>tobase-config; that is the most common cause of pinned apps being MITMed.
Wire it in AndroidManifest.xml:
<application
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="false"
... >2. iOS: App Transport Security (ATS)
Keep ATS on. The minimum acceptable Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<!-- If you truly need a narrow exception, scope it: -->
<key>NSExceptionDomains</key>
<dict>
<key>legacy.partner.example</key>
<dict>
<key>NSIncludesSubdomains</key><true/>
<key>NSExceptionMinimumTLSVersion</key><string>TLSv1.2</string>
<key>NSExceptionAllowsInsecureHTTPLoads</key><false/>
</dict>
</dict>
</dict>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).
- Neither platform can fully block a rooted / jailbroken device from MITMing your traffic. Layer attestation (api-abuse-protection).
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/setAllowUniversalAccessFromFileURLson Android. - On iOS, prefer
ASWebAuthenticationSessionorSFSafariViewControllerfor 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.jsonor/.well-known/apple-app-site-association. - Validate any deep-link parameters server-side before acting on them — never trust an
amountortofield just because it arrived via the registered scheme.
7. Flutter / RN Specific
- Flutter's
dart:ioHttpClientrespects Android NSC but not iOS ATS in every version — verify on your target. Preferdart:ioon iOS going throughURLSessionvia a native plugin for anything sensitive. - React Native's JS
fetchgoes through OkHttp (Android) / NSURLSession (iOS), so platform config applies.XMLHttpRequestfor legacy libraries takes the same path.
Checklist
- [ ]
network_security_config.xmlships withcleartextTrafficPermitted="false"and no user CAs inbase-config. - [ ]
android:usesCleartextTraffic="false"in the manifest. - [ ]
NSAllowsArbitraryLoadsisfalse; anyNSExceptionDomainsare 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.

