@wazir-dev/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,1520 @@
|
|
|
1
|
+
# Mobile Network Security
|
|
2
|
+
|
|
3
|
+
> Expertise module for AI agents implementing secure network communication in mobile applications.
|
|
4
|
+
> Covers iOS, Android, Flutter, and React Native platforms with defense-in-depth strategies.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Threat Landscape
|
|
9
|
+
|
|
10
|
+
Mobile applications transmit sensitive data over networks that are inherently hostile. Unlike
|
|
11
|
+
desktop applications operating behind corporate firewalls, mobile apps routinely connect through
|
|
12
|
+
untrusted public WiFi, cellular networks subject to interception, and compromised network
|
|
13
|
+
infrastructure. The attack surface includes every hop between the device and the backend.
|
|
14
|
+
|
|
15
|
+
### 1.1 Man-in-the-Middle (MITM) on Public WiFi
|
|
16
|
+
|
|
17
|
+
Public WiFi networks are the most common attack vector for mobile traffic interception. Attackers
|
|
18
|
+
deploy evil twin access points -- rogue hotspots mimicking legitimate network names such as
|
|
19
|
+
"StarbucksFreeWiFi" or "Airport_Free_WiFi" -- to lure users into connecting. Once connected,
|
|
20
|
+
all unencrypted traffic is visible to the attacker.
|
|
21
|
+
|
|
22
|
+
**Attack flow:**
|
|
23
|
+
1. Attacker sets up a rogue access point with a familiar SSID.
|
|
24
|
+
2. Victim device auto-connects (many devices rejoin known SSIDs automatically).
|
|
25
|
+
3. Attacker runs ARP spoofing to position themselves between the victim and the gateway.
|
|
26
|
+
4. All HTTP traffic is captured; HTTPS traffic is targeted via SSL stripping or certificate forgery.
|
|
27
|
+
|
|
28
|
+
### 1.2 SSL Stripping
|
|
29
|
+
|
|
30
|
+
SSL stripping downgrades HTTPS connections to HTTP by intercepting the initial HTTP request
|
|
31
|
+
before the TLS handshake occurs. Tools like `sslstrip` automate this attack. The attacker proxies
|
|
32
|
+
the connection, maintaining HTTPS to the server but serving HTTP to the victim.
|
|
33
|
+
|
|
34
|
+
**Impact:** Users see no padlock icon but rarely notice on mobile browsers where the address bar
|
|
35
|
+
is minimal. Apps using HTTP fallback are silently downgraded.
|
|
36
|
+
|
|
37
|
+
### 1.3 Certificate Pinning Bypass
|
|
38
|
+
|
|
39
|
+
Even apps implementing certificate pinning can be compromised on rooted/jailbroken devices.
|
|
40
|
+
Attackers use dynamic instrumentation frameworks:
|
|
41
|
+
|
|
42
|
+
- **Frida**: Injects JavaScript into running processes to hook SSL validation functions.
|
|
43
|
+
- **Objection**: Built on Frida, automates SSL pinning bypass with a single command.
|
|
44
|
+
- **Xposed Framework**: Android module-based hooking of TrustManager implementations.
|
|
45
|
+
|
|
46
|
+
Bypass techniques include modifying the app's TrustManager validation logic, replacing pinned
|
|
47
|
+
certificates stored in `res/raw/` or `assets/`, and altering or removing pins in Android's
|
|
48
|
+
Network Security Configuration XML.
|
|
49
|
+
|
|
50
|
+
### 1.4 Insecure API Calls
|
|
51
|
+
|
|
52
|
+
Common API security failures in mobile apps:
|
|
53
|
+
- Hardcoded API keys in client code (extractable via reverse engineering).
|
|
54
|
+
- Bearer tokens transmitted over HTTP instead of HTTPS.
|
|
55
|
+
- API endpoints accepting requests without mutual TLS or token validation.
|
|
56
|
+
- Lack of request signing allowing replay attacks.
|
|
57
|
+
|
|
58
|
+
### 1.5 Data Leakage Through Analytics SDKs
|
|
59
|
+
|
|
60
|
+
Third-party analytics SDKs are a significant and often overlooked source of data leakage:
|
|
61
|
+
|
|
62
|
+
- **Glassbox SDK incident**: Airlines, hotels, banks, and carriers used Glassbox for "session
|
|
63
|
+
replays," which recorded user screens including passwords, credit card numbers, and taps
|
|
64
|
+
without disclosure in privacy policies.
|
|
65
|
+
- **Baidu Push SDK**: Palo Alto Networks Unit 42 discovered Android apps (Baidu Search Box,
|
|
66
|
+
Baidu Maps -- 6 million US downloads combined) leaking MAC addresses, carrier information,
|
|
67
|
+
and IMSI numbers through the SDK.
|
|
68
|
+
- **FTC enforcement (2024)**: The FTC took action against X-Mode and InMarket for SDKs that
|
|
69
|
+
unfairly collected and used personal information obtained through host apps.
|
|
70
|
+
|
|
71
|
+
**Risk:** SDK network traffic often bypasses the app's own security controls, using separate
|
|
72
|
+
TLS configurations or even transmitting data in cleartext.
|
|
73
|
+
|
|
74
|
+
### 1.6 Real-World Incidents
|
|
75
|
+
|
|
76
|
+
| Year | Incident | Impact |
|
|
77
|
+
|------|----------|--------|
|
|
78
|
+
| 2017 | Banking apps (HSBC, NatWest, Co-op, Santander) found vulnerable to MITM due to improper hostname verification despite certificate pinning | Credentials of millions of users at risk |
|
|
79
|
+
| 2019 | Glassbox analytics SDK recording user screens in major apps (Air Canada, Expedia, Hotels.com) | Passwords and credit card data exposed |
|
|
80
|
+
| 2020 | Baidu SDK data exfiltration in Google Play apps | Device identifiers leaked to third parties |
|
|
81
|
+
| 2024 | AT&T breach -- hackers extracted call and messaging metadata for 110M customers | Massive metadata exposure |
|
|
82
|
+
| 2024 | FTC enforcement against X-Mode/InMarket SDKs for unauthorized location data collection | Regulatory action, consent requirements |
|
|
83
|
+
| 2024 | Multiple banking apps discovered transmitting session tokens over unencrypted WebSocket connections | Session hijacking risk |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 2. Core Security Principles
|
|
88
|
+
|
|
89
|
+
### 2.1 TLS Everywhere
|
|
90
|
+
|
|
91
|
+
Every network connection from a mobile app must use TLS 1.2 at minimum, with TLS 1.3 strongly
|
|
92
|
+
preferred. There are zero valid exceptions for production apps.
|
|
93
|
+
|
|
94
|
+
**Non-negotiable rules:**
|
|
95
|
+
- No HTTP connections, even for seemingly non-sensitive resources (images, configs).
|
|
96
|
+
- No TLS fallback to older versions (SSLv3, TLS 1.0, TLS 1.1 are deprecated).
|
|
97
|
+
- Strong cipher suites only: AES-256-GCM, ChaCha20-Poly1305.
|
|
98
|
+
- Forward secrecy via ECDHE key exchange.
|
|
99
|
+
|
|
100
|
+
### 2.2 Certificate Pinning
|
|
101
|
+
|
|
102
|
+
Certificate pinning restricts which certificates the app trusts, preventing MITM attacks even
|
|
103
|
+
when an attacker has installed a rogue CA on the device.
|
|
104
|
+
|
|
105
|
+
**Pinning strategies (ordered by recommendation):**
|
|
106
|
+
1. **SPKI (Subject Public Key Info) pinning** -- Pin the hash of the public key. Survives
|
|
107
|
+
certificate renewal as long as the same key pair is used. Recommended approach.
|
|
108
|
+
2. **Certificate pinning** -- Pin the entire leaf certificate. Requires app update on every
|
|
109
|
+
certificate rotation. Brittle but simple.
|
|
110
|
+
3. **CA pinning** -- Pin the intermediate or root CA certificate. Broadest trust, least
|
|
111
|
+
protection, but most operationally resilient.
|
|
112
|
+
|
|
113
|
+
**Best practice:** Pin at least two SPKI hashes (current + backup key) and include the
|
|
114
|
+
intermediate CA pin as a fallback. Store pins outside the binary where possible (remote config
|
|
115
|
+
with integrity verification).
|
|
116
|
+
|
|
117
|
+
### 2.3 Certificate Transparency
|
|
118
|
+
|
|
119
|
+
Certificate Transparency (CT) is a public logging framework that enables detection of
|
|
120
|
+
misissued or rogue certificates.
|
|
121
|
+
|
|
122
|
+
**Platform enforcement status (2024-2025):**
|
|
123
|
+
- **Apple (iOS/macOS)**: All publicly trusted TLS certificates must comply with Apple's CT
|
|
124
|
+
policy. Non-compliant certificates cause TLS connection failure. Enforced system-wide.
|
|
125
|
+
- **Android**: CT support rolling out in Android 16+. Apps can opt in to CT enforcement for
|
|
126
|
+
all connections or specific domains.
|
|
127
|
+
- **Chrome/Firefox**: Chrome requires CT for all certificates. Firefox 135+ (Feb 2025) began
|
|
128
|
+
requiring CT for certificates in Mozilla's Root CA Program.
|
|
129
|
+
|
|
130
|
+
**Scale:** Over 17 billion certificates have been logged in CT logs. CT was awarded the
|
|
131
|
+
Levchin Prize in 2024 for its critical role in internet security.
|
|
132
|
+
|
|
133
|
+
### 2.4 No Cleartext Traffic
|
|
134
|
+
|
|
135
|
+
Both iOS and Android provide platform-level mechanisms to block cleartext HTTP:
|
|
136
|
+
- **iOS**: App Transport Security (ATS) blocks HTTP by default since iOS 9.
|
|
137
|
+
- **Android**: `android:usesCleartextTraffic="false"` in the manifest (default `false` for
|
|
138
|
+
apps targeting API 28+).
|
|
139
|
+
|
|
140
|
+
**Rule:** Never add ATS exceptions or enable cleartext traffic in production builds.
|
|
141
|
+
|
|
142
|
+
### 2.5 Secure WebSocket Connections
|
|
143
|
+
|
|
144
|
+
WebSocket connections must use `wss://` (WebSocket Secure) exclusively. Apply the same TLS
|
|
145
|
+
and pinning requirements as HTTPS connections. WebSocket libraries often have separate TLS
|
|
146
|
+
configuration that must be explicitly set -- do not assume they inherit the app's HTTP client
|
|
147
|
+
settings.
|
|
148
|
+
|
|
149
|
+
### 2.6 DNS-over-HTTPS (DoH)
|
|
150
|
+
|
|
151
|
+
Traditional DNS queries are sent in cleartext, enabling DNS spoofing and surveillance.
|
|
152
|
+
DNS-over-HTTPS encrypts DNS resolution within HTTPS.
|
|
153
|
+
|
|
154
|
+
**Implementation considerations for mobile:**
|
|
155
|
+
- Use trusted DoH resolvers: Cloudflare (1.1.1.1), Google (8.8.8.8), Quad9 (9.9.9.9).
|
|
156
|
+
- DoH adds TLS overhead; use HTTP/2 connection reuse to amortize cost.
|
|
157
|
+
- Mobile devices may experience increased battery drain from encryption overhead.
|
|
158
|
+
- Enterprise environments may conflict with DoH -- provide configuration options.
|
|
159
|
+
- Over 90% of Firefox users in the US use DoH by default as of 2024.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 3. Implementation Patterns
|
|
164
|
+
|
|
165
|
+
### 3.1 iOS: App Transport Security (ATS) Configuration
|
|
166
|
+
|
|
167
|
+
ATS is enabled by default. The correct approach is to NOT add exceptions.
|
|
168
|
+
|
|
169
|
+
**Info.plist -- Production (secure, no exceptions needed):**
|
|
170
|
+
```xml
|
|
171
|
+
<!-- ATS is enabled by default. No NSAppTransportSecurity key needed. -->
|
|
172
|
+
<!-- Adding this key with exceptions WEAKENS security. -->
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Info.plist -- If exceptions are absolutely required (e.g., third-party SDK):**
|
|
176
|
+
```xml
|
|
177
|
+
<key>NSAppTransportSecurity</key>
|
|
178
|
+
<dict>
|
|
179
|
+
<!-- Never set NSAllowsArbitraryLoads to true in production -->
|
|
180
|
+
<key>NSExceptionDomains</key>
|
|
181
|
+
<dict>
|
|
182
|
+
<key>legacy-api.example.com</key>
|
|
183
|
+
<dict>
|
|
184
|
+
<key>NSExceptionMinimumTLSVersion</key>
|
|
185
|
+
<string>TLSv1.2</string>
|
|
186
|
+
<key>NSExceptionRequiresForwardSecrecy</key>
|
|
187
|
+
<true/>
|
|
188
|
+
</dict>
|
|
189
|
+
</dict>
|
|
190
|
+
</dict>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Critical ATS rules:**
|
|
194
|
+
- `NSAllowsArbitraryLoads = true` disables ATS entirely. Apple rejects apps using this
|
|
195
|
+
without justification.
|
|
196
|
+
- `NSAllowsLocalNetworking` can be set to `true` for development but must be removed in
|
|
197
|
+
production.
|
|
198
|
+
- Each exception domain must have documented justification for App Store review.
|
|
199
|
+
|
|
200
|
+
### 3.2 Android: Network Security Configuration
|
|
201
|
+
|
|
202
|
+
**res/xml/network_security_config.xml -- Production:**
|
|
203
|
+
```xml
|
|
204
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
205
|
+
<network-security-config>
|
|
206
|
+
<!-- Block all cleartext traffic -->
|
|
207
|
+
<base-config cleartextTrafficPermitted="false">
|
|
208
|
+
<trust-anchors>
|
|
209
|
+
<certificates src="system" />
|
|
210
|
+
</trust-anchors>
|
|
211
|
+
</base-config>
|
|
212
|
+
|
|
213
|
+
<!-- Certificate pinning for your API domain -->
|
|
214
|
+
<domain-config>
|
|
215
|
+
<domain includeSubdomains="true">api.example.com</domain>
|
|
216
|
+
<pin-set expiration="2025-06-01">
|
|
217
|
+
<!-- Primary leaf certificate SPKI hash -->
|
|
218
|
+
<pin digest="SHA-256">k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=</pin>
|
|
219
|
+
<!-- Backup key SPKI hash -->
|
|
220
|
+
<pin digest="SHA-256">VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=</pin>
|
|
221
|
+
</pin-set>
|
|
222
|
+
</domain-config>
|
|
223
|
+
|
|
224
|
+
<!-- Debug overrides - ONLY for debug builds -->
|
|
225
|
+
<debug-overrides>
|
|
226
|
+
<trust-anchors>
|
|
227
|
+
<certificates src="user" />
|
|
228
|
+
</trust-anchors>
|
|
229
|
+
</debug-overrides>
|
|
230
|
+
</network-security-config>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**AndroidManifest.xml reference:**
|
|
234
|
+
```xml
|
|
235
|
+
<application
|
|
236
|
+
android:networkSecurityConfig="@xml/network_security_config"
|
|
237
|
+
android:usesCleartextTraffic="false"
|
|
238
|
+
... >
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Critical rules:**
|
|
242
|
+
- Always set `cleartextTrafficPermitted="false"` in the base config.
|
|
243
|
+
- Pin expiration dates should align with certificate rotation schedules.
|
|
244
|
+
- Debug overrides with user certificates are acceptable for testing but must be in
|
|
245
|
+
`<debug-overrides>` only (never in `<base-config>`).
|
|
246
|
+
- Targeting API level 28+ sets `usesCleartextTraffic` to `false` by default.
|
|
247
|
+
|
|
248
|
+
### 3.3 Certificate Pinning -- Native Implementations
|
|
249
|
+
|
|
250
|
+
#### OkHttp (Android/Kotlin)
|
|
251
|
+
```kotlin
|
|
252
|
+
import okhttp3.CertificatePinner
|
|
253
|
+
import okhttp3.OkHttpClient
|
|
254
|
+
|
|
255
|
+
val certificatePinner = CertificatePinner.Builder()
|
|
256
|
+
.add(
|
|
257
|
+
"api.example.com",
|
|
258
|
+
"sha256/k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=", // leaf
|
|
259
|
+
"sha256/VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=" // backup
|
|
260
|
+
)
|
|
261
|
+
.build()
|
|
262
|
+
|
|
263
|
+
val client = OkHttpClient.Builder()
|
|
264
|
+
.certificatePinner(certificatePinner)
|
|
265
|
+
.connectionSpecs(listOf(ConnectionSpec.MODERN_TLS)) // TLS 1.2+ only
|
|
266
|
+
.build()
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### URLSession (iOS/Swift)
|
|
270
|
+
```swift
|
|
271
|
+
import Foundation
|
|
272
|
+
import CryptoKit
|
|
273
|
+
|
|
274
|
+
class PinnedSessionDelegate: NSObject, URLSessionDelegate {
|
|
275
|
+
// SHA-256 hashes of expected SPKI (Subject Public Key Info)
|
|
276
|
+
private let pinnedHashes: Set<String> = [
|
|
277
|
+
"k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=", // leaf
|
|
278
|
+
"VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=" // backup
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
func urlSession(
|
|
282
|
+
_ session: URLSession,
|
|
283
|
+
didReceive challenge: URLAuthenticationChallenge,
|
|
284
|
+
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
|
285
|
+
) {
|
|
286
|
+
guard challenge.protectionSpace.authenticationMethod ==
|
|
287
|
+
NSURLAuthenticationMethodServerTrust,
|
|
288
|
+
let serverTrust = challenge.protectionSpace.serverTrust else {
|
|
289
|
+
completionHandler(.cancelAuthenticationChallenge, nil)
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Evaluate server trust
|
|
294
|
+
let policies = [SecPolicyCreateSSL(true, challenge.protectionSpace.host as CFString)]
|
|
295
|
+
SecTrustSetPolicies(serverTrust, policies as CFTypeRef)
|
|
296
|
+
|
|
297
|
+
var error: CFError?
|
|
298
|
+
guard SecTrustEvaluateWithError(serverTrust, &error) else {
|
|
299
|
+
completionHandler(.cancelAuthenticationChallenge, nil)
|
|
300
|
+
return
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Extract and verify public key hash
|
|
304
|
+
let certificateCount = SecTrustGetCertificateCount(serverTrust)
|
|
305
|
+
var pinVerified = false
|
|
306
|
+
|
|
307
|
+
for i in 0..<certificateCount {
|
|
308
|
+
guard let certificate = SecTrustCopyCertificateChain(serverTrust)
|
|
309
|
+
.map({ $0 as! [SecCertificate] })?[safe: i],
|
|
310
|
+
let publicKey = SecCertificateCopyKey(certificate),
|
|
311
|
+
let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil) else {
|
|
312
|
+
continue
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let keyHash = SHA256.hash(data: publicKeyData as Data)
|
|
316
|
+
let hashString = Data(keyHash).base64EncodedString()
|
|
317
|
+
|
|
318
|
+
if pinnedHashes.contains(hashString) {
|
|
319
|
+
pinVerified = true
|
|
320
|
+
break
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if pinVerified {
|
|
325
|
+
completionHandler(.useCredential, URLCredential(trust: serverTrust))
|
|
326
|
+
} else {
|
|
327
|
+
completionHandler(.cancelAuthenticationChallenge, nil)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Usage
|
|
333
|
+
let session = URLSession(
|
|
334
|
+
configuration: .default,
|
|
335
|
+
delegate: PinnedSessionDelegate(),
|
|
336
|
+
delegateQueue: nil
|
|
337
|
+
)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### 3.4 TLS Version Enforcement
|
|
341
|
+
|
|
342
|
+
#### Android (OkHttp)
|
|
343
|
+
```kotlin
|
|
344
|
+
val restrictedSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
|
345
|
+
.tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_3)
|
|
346
|
+
.cipherSuites(
|
|
347
|
+
CipherSuite.TLS_AES_128_GCM_SHA256,
|
|
348
|
+
CipherSuite.TLS_AES_256_GCM_SHA384,
|
|
349
|
+
CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
|
|
350
|
+
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
351
|
+
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
352
|
+
)
|
|
353
|
+
.build()
|
|
354
|
+
|
|
355
|
+
val client = OkHttpClient.Builder()
|
|
356
|
+
.connectionSpecs(listOf(restrictedSpec))
|
|
357
|
+
.build()
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
#### iOS (URLSession)
|
|
361
|
+
TLS version is controlled via ATS. Programmatic enforcement:
|
|
362
|
+
```swift
|
|
363
|
+
let config = URLSessionConfiguration.default
|
|
364
|
+
config.tlsMinimumSupportedProtocolVersion = .TLSv12
|
|
365
|
+
config.tlsMaximumSupportedProtocolVersion = .TLSv13
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 3.5 Proxy Detection
|
|
369
|
+
|
|
370
|
+
Detect if the device is configured to route traffic through a proxy (potential interception):
|
|
371
|
+
|
|
372
|
+
#### Android (Kotlin)
|
|
373
|
+
```kotlin
|
|
374
|
+
fun isProxyConfigured(): Boolean {
|
|
375
|
+
val proxyHost = System.getProperty("http.proxyHost")
|
|
376
|
+
val proxyPort = System.getProperty("http.proxyPort")
|
|
377
|
+
return !proxyHost.isNullOrEmpty() && !proxyPort.isNullOrEmpty()
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
fun getWifiProxyInfo(context: Context): Boolean {
|
|
381
|
+
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE)
|
|
382
|
+
as ConnectivityManager
|
|
383
|
+
val network = connectivityManager.activeNetwork ?: return false
|
|
384
|
+
val linkProperties = connectivityManager.getLinkProperties(network) ?: return false
|
|
385
|
+
return linkProperties.httpProxy != null
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
#### iOS (Swift)
|
|
390
|
+
```swift
|
|
391
|
+
func isProxyConfigured() -> Bool {
|
|
392
|
+
guard let proxySettings = CFNetworkCopySystemProxySettings()?.takeRetainedValue()
|
|
393
|
+
as? [String: Any] else {
|
|
394
|
+
return false
|
|
395
|
+
}
|
|
396
|
+
if let httpProxy = proxySettings["HTTPProxy"] as? String, !httpProxy.isEmpty {
|
|
397
|
+
return true
|
|
398
|
+
}
|
|
399
|
+
if let httpsProxy = proxySettings["HTTPSProxy"] as? String, !httpsProxy.isEmpty {
|
|
400
|
+
return true
|
|
401
|
+
}
|
|
402
|
+
return false
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**Warning:** Proxy detection should be used for risk assessment and telemetry, not as a hard
|
|
407
|
+
block. Legitimate users may use VPNs or corporate proxies. Combine with other signals.
|
|
408
|
+
|
|
409
|
+
### 3.6 VPN Detection
|
|
410
|
+
|
|
411
|
+
#### Android (Kotlin)
|
|
412
|
+
```kotlin
|
|
413
|
+
fun isVpnActive(context: Context): Boolean {
|
|
414
|
+
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE)
|
|
415
|
+
as ConnectivityManager
|
|
416
|
+
val activeNetwork = connectivityManager.activeNetwork ?: return false
|
|
417
|
+
val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
|
|
418
|
+
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
#### iOS (Swift)
|
|
423
|
+
```swift
|
|
424
|
+
func isVpnActive() -> Bool {
|
|
425
|
+
guard let proxySettings = CFNetworkCopySystemProxySettings()?.takeRetainedValue()
|
|
426
|
+
as? [String: Any],
|
|
427
|
+
let scoped = proxySettings["__SCOPED__"] as? [String: Any] else {
|
|
428
|
+
return false
|
|
429
|
+
}
|
|
430
|
+
return scoped.keys.contains { key in
|
|
431
|
+
key.contains("tap") || key.contains("tun") || key.contains("ppp") ||
|
|
432
|
+
key.contains("ipsec") || key.contains("utun")
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 3.7 Network Traffic Monitoring Prevention
|
|
438
|
+
|
|
439
|
+
To make it harder for attackers to intercept and analyze traffic:
|
|
440
|
+
|
|
441
|
+
- **Disable debugging in release builds**: Remove all logging of network requests/responses.
|
|
442
|
+
- **Obfuscate API endpoints**: Do not store full URLs as string literals.
|
|
443
|
+
- **Implement request signing**: HMAC-based request signing prevents tampering.
|
|
444
|
+
- **Use binary protocols**: Protocol Buffers or MessagePack instead of JSON reduce readability
|
|
445
|
+
of intercepted traffic (security through obscurity -- supplementary only).
|
|
446
|
+
- **Detect Frida/instrumentation**: Check for Frida artifacts on Android (frida-server port
|
|
447
|
+
27042, Frida libraries in `/proc/self/maps`).
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## 4. Vulnerability Catalog
|
|
452
|
+
|
|
453
|
+
### V-01: Cleartext HTTP Traffic
|
|
454
|
+
|
|
455
|
+
**Severity:** Critical
|
|
456
|
+
**OWASP:** M5 - Insecure Communication
|
|
457
|
+
**Description:** App transmits data over unencrypted HTTP connections.
|
|
458
|
+
|
|
459
|
+
```kotlin
|
|
460
|
+
// INSECURE - cleartext HTTP
|
|
461
|
+
val url = "http://api.example.com/login"
|
|
462
|
+
val request = Request.Builder().url(url).build()
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
```kotlin
|
|
466
|
+
// SECURE - HTTPS only
|
|
467
|
+
val url = "https://api.example.com/login"
|
|
468
|
+
val request = Request.Builder().url(url).build()
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**Detection:** Network traffic analysis with mitmproxy or Wireshark. Android lint rule
|
|
472
|
+
`UsingHttp`.
|
|
473
|
+
|
|
474
|
+
### V-02: Disabled Certificate Validation
|
|
475
|
+
|
|
476
|
+
**Severity:** Critical
|
|
477
|
+
**OWASP:** M5 - Insecure Communication
|
|
478
|
+
**Description:** App accepts any certificate, including self-signed or expired.
|
|
479
|
+
|
|
480
|
+
```kotlin
|
|
481
|
+
// INSECURE - trusts all certificates (common in debug code left in production)
|
|
482
|
+
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
|
|
483
|
+
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
|
|
484
|
+
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
|
|
485
|
+
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
|
|
486
|
+
})
|
|
487
|
+
val sslContext = SSLContext.getInstance("TLS")
|
|
488
|
+
sslContext.init(null, trustAllCerts, SecureRandom())
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
```kotlin
|
|
492
|
+
// SECURE - use system trust manager with certificate pinning
|
|
493
|
+
val client = OkHttpClient.Builder()
|
|
494
|
+
.certificatePinner(
|
|
495
|
+
CertificatePinner.Builder()
|
|
496
|
+
.add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
|
|
497
|
+
.build()
|
|
498
|
+
)
|
|
499
|
+
.build()
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### V-03: Weak TLS Versions
|
|
503
|
+
|
|
504
|
+
**Severity:** High
|
|
505
|
+
**Description:** App allows TLS 1.0 or 1.1, which have known vulnerabilities (BEAST, POODLE).
|
|
506
|
+
|
|
507
|
+
```swift
|
|
508
|
+
// INSECURE - allows TLS 1.0
|
|
509
|
+
let config = URLSessionConfiguration.default
|
|
510
|
+
config.tlsMinimumSupportedProtocolVersion = .TLSv10
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
```swift
|
|
514
|
+
// SECURE - TLS 1.2 minimum
|
|
515
|
+
let config = URLSessionConfiguration.default
|
|
516
|
+
config.tlsMinimumSupportedProtocolVersion = .TLSv12
|
|
517
|
+
config.tlsMaximumSupportedProtocolVersion = .TLSv13
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### V-04: Missing Certificate Pinning
|
|
521
|
+
|
|
522
|
+
**Severity:** High
|
|
523
|
+
**OWASP:** M5 - Insecure Communication
|
|
524
|
+
**Description:** App relies solely on the system trust store, which can be compromised by
|
|
525
|
+
user-installed CA certificates.
|
|
526
|
+
|
|
527
|
+
**Impact:** Attackers on the same network can install a proxy CA certificate and intercept
|
|
528
|
+
all HTTPS traffic.
|
|
529
|
+
|
|
530
|
+
**Fix:** Implement SPKI pinning with backup pins (see Section 3.3).
|
|
531
|
+
|
|
532
|
+
### V-05: MITM via HTTP Proxy
|
|
533
|
+
|
|
534
|
+
**Severity:** High
|
|
535
|
+
**Description:** App does not detect or respond to proxy configurations that could indicate
|
|
536
|
+
traffic interception.
|
|
537
|
+
|
|
538
|
+
**Mitigation:** Implement proxy detection (Section 3.5) and increase security posture when
|
|
539
|
+
a proxy is detected (additional token validation, reduced session lifetime).
|
|
540
|
+
|
|
541
|
+
### V-06: DNS Spoofing
|
|
542
|
+
|
|
543
|
+
**Severity:** Medium-High
|
|
544
|
+
**Description:** DNS queries are sent in cleartext, allowing attackers to redirect the app
|
|
545
|
+
to malicious servers.
|
|
546
|
+
|
|
547
|
+
**Mitigation:** Implement DNS-over-HTTPS (Section 2.6). Validate server identity through
|
|
548
|
+
certificate pinning regardless of DNS resolution.
|
|
549
|
+
|
|
550
|
+
### V-07: Insecure WebSocket Connections
|
|
551
|
+
|
|
552
|
+
**Severity:** High
|
|
553
|
+
**Description:** App uses `ws://` instead of `wss://` for WebSocket connections, or uses
|
|
554
|
+
`wss://` without certificate pinning.
|
|
555
|
+
|
|
556
|
+
```javascript
|
|
557
|
+
// INSECURE - unencrypted WebSocket
|
|
558
|
+
const ws = new WebSocket('ws://api.example.com/stream');
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
```javascript
|
|
562
|
+
// SECURE - encrypted WebSocket
|
|
563
|
+
const ws = new WebSocket('wss://api.example.com/stream');
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Note:** WebSocket libraries often have separate TLS configuration. Verify that pinning
|
|
567
|
+
applies to WebSocket connections, not just HTTP.
|
|
568
|
+
|
|
569
|
+
### V-08: Analytics SDK Data Leakage
|
|
570
|
+
|
|
571
|
+
**Severity:** High
|
|
572
|
+
**Description:** Third-party analytics SDKs transmit user data (PII, device identifiers,
|
|
573
|
+
screen recordings) without adequate encryption or user consent.
|
|
574
|
+
|
|
575
|
+
**Mitigation:**
|
|
576
|
+
- Audit all SDK network traffic before integration.
|
|
577
|
+
- Use SDK proxy configurations to route through your security controls.
|
|
578
|
+
- Implement data loss prevention rules for outbound traffic.
|
|
579
|
+
- Review SDK privacy policies and data handling practices.
|
|
580
|
+
- Prefer privacy-focused analytics (Plausible, Matomo) over invasive SDKs.
|
|
581
|
+
|
|
582
|
+
### V-09: Hardcoded API Keys and Secrets
|
|
583
|
+
|
|
584
|
+
**Severity:** High
|
|
585
|
+
**Description:** API keys, tokens, or secrets embedded in app binary are extractable
|
|
586
|
+
through reverse engineering.
|
|
587
|
+
|
|
588
|
+
```kotlin
|
|
589
|
+
// INSECURE - hardcoded API key
|
|
590
|
+
val apiKey = "REDACTED_STRIPE_KEY"
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
```kotlin
|
|
594
|
+
// SECURE - fetch from secure backend, store in encrypted storage
|
|
595
|
+
val apiKey = SecureTokenStore.getApiKey() // Retrieved from server, stored in Keystore
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### V-10: Missing Hostname Verification
|
|
599
|
+
|
|
600
|
+
**Severity:** Critical
|
|
601
|
+
**Description:** App validates the certificate but does not verify the hostname matches
|
|
602
|
+
the certificate's Common Name or Subject Alternative Name.
|
|
603
|
+
|
|
604
|
+
This was the exact vulnerability found in banking apps for HSBC, NatWest, Co-op, Santander,
|
|
605
|
+
and Allied Irish Bank in 2017 -- apps pinned certificates but accepted them for any hostname.
|
|
606
|
+
|
|
607
|
+
```kotlin
|
|
608
|
+
// INSECURE - disabled hostname verification
|
|
609
|
+
val client = OkHttpClient.Builder()
|
|
610
|
+
.hostnameVerifier { _, _ -> true }
|
|
611
|
+
.build()
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
```kotlin
|
|
615
|
+
// SECURE - default hostname verification (OkHttp does this by default)
|
|
616
|
+
val client = OkHttpClient.Builder()
|
|
617
|
+
.build() // Default OkHostnameVerifier is used
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### V-11: Improper Certificate Rotation Handling
|
|
621
|
+
|
|
622
|
+
**Severity:** Medium
|
|
623
|
+
**Description:** Certificate pinning with a single pin and no backup causes app outage
|
|
624
|
+
when the certificate is rotated.
|
|
625
|
+
|
|
626
|
+
**Mitigation:** Always pin multiple keys (current + backup). Set reasonable pin expiration
|
|
627
|
+
dates. Implement graceful degradation with enhanced monitoring when pins expire.
|
|
628
|
+
|
|
629
|
+
### V-12: Sensitive Data in URL Parameters
|
|
630
|
+
|
|
631
|
+
**Severity:** Medium
|
|
632
|
+
**Description:** Tokens, credentials, or PII passed as URL query parameters are logged in
|
|
633
|
+
server access logs, proxy logs, browser history, and referrer headers.
|
|
634
|
+
|
|
635
|
+
```kotlin
|
|
636
|
+
// INSECURE - token in URL
|
|
637
|
+
val url = "https://api.example.com/user?token=abc123&ssn=123-45-6789"
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
```kotlin
|
|
641
|
+
// SECURE - sensitive data in headers or POST body
|
|
642
|
+
val request = Request.Builder()
|
|
643
|
+
.url("https://api.example.com/user")
|
|
644
|
+
.header("Authorization", "Bearer abc123")
|
|
645
|
+
.build()
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### V-13: Insufficient Network Error Handling
|
|
649
|
+
|
|
650
|
+
**Severity:** Medium
|
|
651
|
+
**Description:** App displays detailed TLS error messages to users, revealing implementation
|
|
652
|
+
details. Or worse, falls back to insecure connections on TLS failure.
|
|
653
|
+
|
|
654
|
+
**Mitigation:** Show generic error messages. Never fall back to HTTP. Log detailed errors
|
|
655
|
+
to secure server-side telemetry only.
|
|
656
|
+
|
|
657
|
+
### V-14: Unprotected Backup Channel Communication
|
|
658
|
+
|
|
659
|
+
**Severity:** Medium
|
|
660
|
+
**Description:** App uses a secondary communication channel (e.g., for crash reporting or
|
|
661
|
+
push notifications) that does not have the same security controls as the primary API channel.
|
|
662
|
+
|
|
663
|
+
**Mitigation:** Apply the same TLS, pinning, and monitoring requirements to all network
|
|
664
|
+
channels, including crash reporters, analytics, push registration, and CDN connections.
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
## 5. Security Checklist
|
|
669
|
+
|
|
670
|
+
Use this checklist during development, code review, and security testing.
|
|
671
|
+
|
|
672
|
+
### Transport Layer
|
|
673
|
+
- [ ] All connections use HTTPS/WSS -- no cleartext HTTP/WS anywhere
|
|
674
|
+
- [ ] TLS 1.2 is the minimum version; TLS 1.3 is preferred
|
|
675
|
+
- [ ] Only strong cipher suites are enabled (AES-GCM, ChaCha20-Poly1305)
|
|
676
|
+
- [ ] Forward secrecy is enforced (ECDHE key exchange)
|
|
677
|
+
- [ ] HSTS headers are configured on all API endpoints
|
|
678
|
+
|
|
679
|
+
### Certificate Security
|
|
680
|
+
- [ ] SPKI certificate pinning is implemented for all API domains
|
|
681
|
+
- [ ] At least two pins are configured (current + backup key)
|
|
682
|
+
- [ ] Pin expiration aligns with certificate rotation schedule
|
|
683
|
+
- [ ] Certificate Transparency is enforced where platform supports it
|
|
684
|
+
- [ ] Hostname verification is not disabled anywhere in the codebase
|
|
685
|
+
|
|
686
|
+
### Platform Configuration
|
|
687
|
+
- [ ] iOS: ATS is enabled with no `NSAllowsArbitraryLoads` exception
|
|
688
|
+
- [ ] Android: `network_security_config.xml` blocks cleartext traffic
|
|
689
|
+
- [ ] Android: Debug-only trust anchors are in `<debug-overrides>` only
|
|
690
|
+
- [ ] No `TrustAllCerts` or `ALLOW_ALL_HOSTNAME_VERIFIER` in codebase
|
|
691
|
+
|
|
692
|
+
### Data Protection
|
|
693
|
+
- [ ] No sensitive data in URL query parameters
|
|
694
|
+
- [ ] API keys and secrets are not hardcoded in the app binary
|
|
695
|
+
- [ ] Request/response logging is disabled in release builds
|
|
696
|
+
- [ ] Error messages do not reveal implementation details
|
|
697
|
+
|
|
698
|
+
### Third-Party SDKs
|
|
699
|
+
- [ ] All SDK network traffic has been audited with a proxy tool
|
|
700
|
+
- [ ] SDKs do not transmit PII without user consent
|
|
701
|
+
- [ ] SDK TLS configurations meet the same standards as app code
|
|
702
|
+
- [ ] SDK privacy policies are reviewed and compliant
|
|
703
|
+
|
|
704
|
+
### Monitoring & Detection
|
|
705
|
+
- [ ] Proxy detection is implemented with appropriate risk response
|
|
706
|
+
- [ ] Certificate pinning failures are reported to server-side telemetry
|
|
707
|
+
- [ ] Network anomalies trigger alerts (unexpected endpoints, protocols)
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
711
|
+
## 6. Tools & Automation
|
|
712
|
+
|
|
713
|
+
### 6.1 Burp Suite (Mobile Testing)
|
|
714
|
+
|
|
715
|
+
The industry-standard proxy for mobile security testing.
|
|
716
|
+
|
|
717
|
+
**Setup for mobile testing:**
|
|
718
|
+
1. Configure Burp as proxy on the testing machine.
|
|
719
|
+
2. Install Burp CA certificate on the mobile device.
|
|
720
|
+
3. Configure device WiFi to use Burp proxy.
|
|
721
|
+
4. For apps with certificate pinning: use Frida to bypass pinning during testing.
|
|
722
|
+
|
|
723
|
+
**Key features:**
|
|
724
|
+
- Intercept and modify HTTPS traffic in real time.
|
|
725
|
+
- Scanner module identifies TLS misconfigurations automatically.
|
|
726
|
+
- Repeater for replaying and modifying API requests.
|
|
727
|
+
- Intruder for automated parameter fuzzing.
|
|
728
|
+
- Extensions: Mobile Assistant for automated device setup.
|
|
729
|
+
|
|
730
|
+
**Command -- extract Burp CA for Android:**
|
|
731
|
+
```bash
|
|
732
|
+
# Export DER certificate and convert for Android system trust store
|
|
733
|
+
openssl x509 -inform DER -in cacert.der -out cacert.pem
|
|
734
|
+
HASH=$(openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1)
|
|
735
|
+
cp cacert.pem "$HASH.0"
|
|
736
|
+
adb push "$HASH.0" /system/etc/security/cacerts/
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
### 6.2 mitmproxy
|
|
740
|
+
|
|
741
|
+
Open-source TLS-intercepting proxy, scriptable with Python.
|
|
742
|
+
|
|
743
|
+
```bash
|
|
744
|
+
# Start mitmproxy in transparent mode
|
|
745
|
+
mitmproxy --mode transparent --showhost
|
|
746
|
+
|
|
747
|
+
# Dump all requests to a file for analysis
|
|
748
|
+
mitmdump -w traffic.flow
|
|
749
|
+
|
|
750
|
+
# Filter for specific domains
|
|
751
|
+
mitmproxy --mode regular --set block_global=false \
|
|
752
|
+
--set upstream_cert=true -k
|
|
753
|
+
|
|
754
|
+
# Script to detect cleartext credentials
|
|
755
|
+
# save as detect_cleartext.py
|
|
756
|
+
# mitmdump -s detect_cleartext.py
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
```python
|
|
760
|
+
# detect_cleartext.py - mitmproxy addon
|
|
761
|
+
from mitmproxy import http
|
|
762
|
+
|
|
763
|
+
SENSITIVE_KEYS = ["password", "token", "secret", "api_key", "credit_card", "ssn"]
|
|
764
|
+
|
|
765
|
+
def request(flow: http.HTTPFlow):
|
|
766
|
+
if flow.request.scheme == "http":
|
|
767
|
+
print(f"[ALERT] Cleartext HTTP: {flow.request.url}")
|
|
768
|
+
|
|
769
|
+
content = flow.request.get_text()
|
|
770
|
+
for key in SENSITIVE_KEYS:
|
|
771
|
+
if key in content.lower():
|
|
772
|
+
print(f"[ALERT] Sensitive data '{key}' in request to {flow.request.url}")
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### 6.3 Charles Proxy
|
|
776
|
+
|
|
777
|
+
GUI-based proxy popular with iOS/macOS developers.
|
|
778
|
+
|
|
779
|
+
**Mobile testing workflow:**
|
|
780
|
+
1. Enable SSL Proxying for target domains (Proxy > SSL Proxying Settings).
|
|
781
|
+
2. Install Charles root certificate on device (chls.pro/ssl).
|
|
782
|
+
3. Map device proxy to Charles (same WiFi network).
|
|
783
|
+
4. Inspect requests, responses, timing, and TLS details.
|
|
784
|
+
5. Use Rewrite tool to test security controls (downgrade attacks, header removal).
|
|
785
|
+
|
|
786
|
+
### 6.4 Wireshark
|
|
787
|
+
|
|
788
|
+
Network protocol analyzer for deep packet inspection.
|
|
789
|
+
|
|
790
|
+
**Mobile capture approaches:**
|
|
791
|
+
- **Android**: Use `tcpdump` on rooted device, pull pcap file for Wireshark analysis.
|
|
792
|
+
- **iOS**: Use `rvictl` to create a virtual interface for a connected iOS device.
|
|
793
|
+
|
|
794
|
+
```bash
|
|
795
|
+
# iOS remote virtual interface capture
|
|
796
|
+
rvictl -s <UDID> # Create virtual interface
|
|
797
|
+
tcpdump -i rvi0 -w capture.pcap # Capture traffic
|
|
798
|
+
rvictl -x <UDID> # Remove interface when done
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
**Wireshark filters for mobile security analysis:**
|
|
802
|
+
```
|
|
803
|
+
# Find cleartext HTTP traffic
|
|
804
|
+
http && !ssl
|
|
805
|
+
|
|
806
|
+
# Find weak TLS versions
|
|
807
|
+
ssl.handshake.version < 0x0303
|
|
808
|
+
|
|
809
|
+
# Find certificate issues
|
|
810
|
+
ssl.alert.message
|
|
811
|
+
|
|
812
|
+
# Find DNS queries (potential spoofing targets)
|
|
813
|
+
dns && dns.flags.response == 0
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
### 6.5 SSL Labs / sslyze
|
|
817
|
+
|
|
818
|
+
Server-side TLS configuration testing.
|
|
819
|
+
|
|
820
|
+
```bash
|
|
821
|
+
# sslyze - test server TLS configuration
|
|
822
|
+
sslyze --regular api.example.com
|
|
823
|
+
|
|
824
|
+
# Check for specific vulnerabilities
|
|
825
|
+
sslyze --heartbleed --openssl_ccs --robot api.example.com
|
|
826
|
+
|
|
827
|
+
# JSON output for CI/CD integration
|
|
828
|
+
sslyze --json_out=results.json api.example.com
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
### 6.6 Frida (Dynamic Instrumentation)
|
|
832
|
+
|
|
833
|
+
Used both offensively (to test pinning) and defensively (to detect instrumentation).
|
|
834
|
+
|
|
835
|
+
```bash
|
|
836
|
+
# Bypass certificate pinning for testing (Android)
|
|
837
|
+
frida -U -f com.example.app -l ssl_pinning_bypass.js --no-pause
|
|
838
|
+
|
|
839
|
+
# Common Frida script targets:
|
|
840
|
+
# - javax.net.ssl.X509TrustManager
|
|
841
|
+
# - okhttp3.CertificatePinner
|
|
842
|
+
# - com.android.org.conscrypt.TrustManagerImpl
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
### 6.7 Automated CI/CD Security Checks
|
|
846
|
+
|
|
847
|
+
```yaml
|
|
848
|
+
# GitHub Actions - mobile network security checks
|
|
849
|
+
- name: Check for cleartext traffic
|
|
850
|
+
run: |
|
|
851
|
+
# Android: Verify network security config
|
|
852
|
+
grep -r "cleartextTrafficPermitted=\"true\"" app/src/main/res/ && exit 1 || true
|
|
853
|
+
|
|
854
|
+
# Check for disabled certificate validation
|
|
855
|
+
grep -rn "TrustAllCerts\|ALLOW_ALL\|trustAllCerts\|setHostnameVerifier" \
|
|
856
|
+
app/src/main/java/ && exit 1 || true
|
|
857
|
+
|
|
858
|
+
# Check for HTTP URLs (should be HTTPS)
|
|
859
|
+
grep -rn "\"http://" app/src/main/java/ | grep -v "https://" && exit 1 || true
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
## 7. Platform-Specific Guidance
|
|
865
|
+
|
|
866
|
+
### 7.1 iOS
|
|
867
|
+
|
|
868
|
+
**URLSession with pinning:**
|
|
869
|
+
See Section 3.3 for the complete `PinnedSessionDelegate` implementation.
|
|
870
|
+
|
|
871
|
+
**TrustKit (recommended library):**
|
|
872
|
+
```swift
|
|
873
|
+
// AppDelegate.swift
|
|
874
|
+
import TrustKit
|
|
875
|
+
|
|
876
|
+
let trustKitConfig: [String: Any] = [
|
|
877
|
+
kTSKSwizzleNetworkDelegates: false,
|
|
878
|
+
kTSKPinnedDomains: [
|
|
879
|
+
"api.example.com": [
|
|
880
|
+
kTSKEnforcePinning: true,
|
|
881
|
+
kTSKIncludeSubdomains: true,
|
|
882
|
+
kTSKPublicKeyHashes: [
|
|
883
|
+
"k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=",
|
|
884
|
+
"VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8="
|
|
885
|
+
],
|
|
886
|
+
kTSKReportUris: ["https://reporting.example.com/pin-failure"]
|
|
887
|
+
]
|
|
888
|
+
]
|
|
889
|
+
]
|
|
890
|
+
TrustKit.initSharedInstance(withConfiguration: trustKitConfig)
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
**Alamofire with server trust evaluation:**
|
|
894
|
+
```swift
|
|
895
|
+
let evaluators: [String: ServerTrustEvaluating] = [
|
|
896
|
+
"api.example.com": PinnedCertificatesTrustEvaluator(
|
|
897
|
+
certificates: Bundle.main.af.certificates,
|
|
898
|
+
acceptSelfSignedCertificates: false,
|
|
899
|
+
performDefaultValidation: true,
|
|
900
|
+
validateHost: true
|
|
901
|
+
)
|
|
902
|
+
]
|
|
903
|
+
let manager = ServerTrustManager(evaluators: evaluators)
|
|
904
|
+
let session = Session(serverTrustManager: manager)
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
**iOS-specific considerations:**
|
|
908
|
+
- ATS handles TLS version enforcement automatically.
|
|
909
|
+
- WKWebView inherits ATS settings; UIWebView (deprecated) does not.
|
|
910
|
+
- Background URLSession tasks maintain pinning through the delegate.
|
|
911
|
+
- Extensions (widgets, notification services) have separate ATS configurations.
|
|
912
|
+
|
|
913
|
+
### 7.2 Android
|
|
914
|
+
|
|
915
|
+
**Retrofit + OkHttp with comprehensive security:**
|
|
916
|
+
```kotlin
|
|
917
|
+
@Module
|
|
918
|
+
@InstallIn(SingletonComponent::class)
|
|
919
|
+
object NetworkModule {
|
|
920
|
+
|
|
921
|
+
@Provides
|
|
922
|
+
@Singleton
|
|
923
|
+
fun provideCertificatePinner(): CertificatePinner =
|
|
924
|
+
CertificatePinner.Builder()
|
|
925
|
+
.add("api.example.com",
|
|
926
|
+
"sha256/k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=",
|
|
927
|
+
"sha256/VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8="
|
|
928
|
+
)
|
|
929
|
+
.build()
|
|
930
|
+
|
|
931
|
+
@Provides
|
|
932
|
+
@Singleton
|
|
933
|
+
fun provideOkHttpClient(pinner: CertificatePinner): OkHttpClient =
|
|
934
|
+
OkHttpClient.Builder()
|
|
935
|
+
.certificatePinner(pinner)
|
|
936
|
+
.connectionSpecs(listOf(ConnectionSpec.MODERN_TLS))
|
|
937
|
+
.connectTimeout(30, TimeUnit.SECONDS)
|
|
938
|
+
.readTimeout(30, TimeUnit.SECONDS)
|
|
939
|
+
.addInterceptor { chain ->
|
|
940
|
+
// Enforce HTTPS
|
|
941
|
+
val request = chain.request()
|
|
942
|
+
require(request.url.scheme == "https") {
|
|
943
|
+
"Cleartext traffic not allowed: ${request.url}"
|
|
944
|
+
}
|
|
945
|
+
chain.proceed(request)
|
|
946
|
+
}
|
|
947
|
+
.build()
|
|
948
|
+
|
|
949
|
+
@Provides
|
|
950
|
+
@Singleton
|
|
951
|
+
fun provideRetrofit(client: OkHttpClient): Retrofit =
|
|
952
|
+
Retrofit.Builder()
|
|
953
|
+
.baseUrl("https://api.example.com/")
|
|
954
|
+
.client(client)
|
|
955
|
+
.addConverterFactory(GsonConverterFactory.create())
|
|
956
|
+
.build()
|
|
957
|
+
}
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
**Android-specific considerations:**
|
|
961
|
+
- Network Security Config is the preferred declarative approach.
|
|
962
|
+
- Apps targeting API 24+ no longer trust user-installed CAs by default.
|
|
963
|
+
- Apps targeting API 28+ block cleartext traffic by default.
|
|
964
|
+
- Android 16+ supports Certificate Transparency opt-in.
|
|
965
|
+
- WorkManager and JobScheduler network requests inherit app-level security config.
|
|
966
|
+
|
|
967
|
+
### 7.3 Flutter (Dart)
|
|
968
|
+
|
|
969
|
+
**Using dart:io SecurityContext:**
|
|
970
|
+
```dart
|
|
971
|
+
import 'dart:io';
|
|
972
|
+
import 'package:flutter/services.dart';
|
|
973
|
+
|
|
974
|
+
class SecureHttpClient {
|
|
975
|
+
static Future<HttpClient> create() async {
|
|
976
|
+
final securityContext = SecurityContext(withTrustedRoots: false);
|
|
977
|
+
|
|
978
|
+
// Load pinned certificate from assets
|
|
979
|
+
final certData = await rootBundle.load('assets/certs/api_cert.pem');
|
|
980
|
+
securityContext.setTrustedCertificatesBytes(certData.buffer.asUint8List());
|
|
981
|
+
|
|
982
|
+
final client = HttpClient(context: securityContext);
|
|
983
|
+
|
|
984
|
+
// Enforce TLS 1.2+
|
|
985
|
+
client.badCertificateCallback = (cert, host, port) => false;
|
|
986
|
+
|
|
987
|
+
return client;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
**Using Dio with certificate pinning:**
|
|
993
|
+
```dart
|
|
994
|
+
import 'package:dio/dio.dart';
|
|
995
|
+
import 'package:dio/io.dart';
|
|
996
|
+
import 'dart:io';
|
|
997
|
+
|
|
998
|
+
Dio createSecureDio() {
|
|
999
|
+
final dio = Dio(BaseOptions(
|
|
1000
|
+
baseUrl: 'https://api.example.com',
|
|
1001
|
+
connectTimeout: const Duration(seconds: 30),
|
|
1002
|
+
receiveTimeout: const Duration(seconds: 30),
|
|
1003
|
+
));
|
|
1004
|
+
|
|
1005
|
+
(dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
|
|
1006
|
+
final client = HttpClient();
|
|
1007
|
+
|
|
1008
|
+
// Certificate pinning callback
|
|
1009
|
+
client.badCertificateCallback = (X509Certificate cert, String host, int port) {
|
|
1010
|
+
// Compare certificate fingerprint
|
|
1011
|
+
final expectedFingerprint = 'AB:CD:EF:...'; // SHA-256 fingerprint
|
|
1012
|
+
return cert.sha256Fingerprint == expectedFingerprint;
|
|
1013
|
+
};
|
|
1014
|
+
|
|
1015
|
+
return client;
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
return dio;
|
|
1019
|
+
}
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
**Flutter-specific considerations:**
|
|
1023
|
+
- Dart's `HttpClient` has its own TLS stack, separate from platform defaults.
|
|
1024
|
+
- Certificate pinning must be configured in Dart code; platform configs (ATS, NSC) do not
|
|
1025
|
+
apply to dart:io connections.
|
|
1026
|
+
- Use `http_certificate_pinning` or `trustpin_sdk` packages for simplified implementation.
|
|
1027
|
+
- Pin SPKI hashes from leaf and intermediate certificates.
|
|
1028
|
+
- Test on both iOS and Android -- TLS behavior may differ across platforms.
|
|
1029
|
+
|
|
1030
|
+
### 7.4 React Native
|
|
1031
|
+
|
|
1032
|
+
**react-native-ssl-public-key-pinning:**
|
|
1033
|
+
```typescript
|
|
1034
|
+
import { fetch as pinnedFetch } from 'react-native-ssl-public-key-pinning';
|
|
1035
|
+
|
|
1036
|
+
// Configure pinning at app startup
|
|
1037
|
+
import { initializeSslPinning } from 'react-native-ssl-public-key-pinning';
|
|
1038
|
+
|
|
1039
|
+
await initializeSslPinning({
|
|
1040
|
+
'api.example.com': {
|
|
1041
|
+
includeSubdomains: true,
|
|
1042
|
+
publicKeyHashes: [
|
|
1043
|
+
'k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=',
|
|
1044
|
+
'VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=',
|
|
1045
|
+
],
|
|
1046
|
+
},
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
// Use the pinned fetch instead of global fetch
|
|
1050
|
+
const response = await pinnedFetch('https://api.example.com/data', {
|
|
1051
|
+
method: 'GET',
|
|
1052
|
+
headers: { 'Authorization': 'Bearer token' },
|
|
1053
|
+
});
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
**react-native-ssl-pinning (OkHttp/AFNetworking based):**
|
|
1057
|
+
```typescript
|
|
1058
|
+
import { fetch } from 'react-native-ssl-pinning';
|
|
1059
|
+
|
|
1060
|
+
const response = await fetch('https://api.example.com/data', {
|
|
1061
|
+
method: 'GET',
|
|
1062
|
+
timeoutInterval: 10000,
|
|
1063
|
+
sslPinning: {
|
|
1064
|
+
certs: ['api_cert'], // .cer files in android/app/src/main/assets/
|
|
1065
|
+
},
|
|
1066
|
+
headers: {
|
|
1067
|
+
'Authorization': 'Bearer token',
|
|
1068
|
+
'Content-Type': 'application/json',
|
|
1069
|
+
},
|
|
1070
|
+
});
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
**React Native-specific considerations:**
|
|
1074
|
+
- JavaScript `fetch()` does not support certificate pinning natively.
|
|
1075
|
+
- Native modules bridge pinning to OkHttp (Android) and AFNetworking/TrustKit (iOS).
|
|
1076
|
+
- Ensure pinning applies to all network libraries used (Axios, Apollo, etc.).
|
|
1077
|
+
- Debug builds should use a separate configuration that allows proxy certificates.
|
|
1078
|
+
- Hermes engine does not affect network security but obfuscates JS for reverse engineering.
|
|
1079
|
+
|
|
1080
|
+
---
|
|
1081
|
+
|
|
1082
|
+
## 8. Incident Patterns
|
|
1083
|
+
|
|
1084
|
+
### 8.1 MITM Detection
|
|
1085
|
+
|
|
1086
|
+
**Server-side indicators:**
|
|
1087
|
+
- Sudden changes in client TLS fingerprints (JA3/JA4 hashes) for the same user.
|
|
1088
|
+
- Requests arriving from unexpected IP ranges or geolocations.
|
|
1089
|
+
- API calls with inconsistent User-Agent strings vs. device attestation.
|
|
1090
|
+
- Certificate pinning failure reports from client telemetry.
|
|
1091
|
+
- Multiple authentication failures from a single IP with different user accounts.
|
|
1092
|
+
|
|
1093
|
+
**Client-side indicators:**
|
|
1094
|
+
- Certificate validation failures (pin mismatch).
|
|
1095
|
+
- Unexpected proxy configuration detected.
|
|
1096
|
+
- Network latency anomalies (proxy adds measurable latency).
|
|
1097
|
+
- DNS resolution returning unexpected IP addresses.
|
|
1098
|
+
|
|
1099
|
+
**Detection implementation:**
|
|
1100
|
+
```kotlin
|
|
1101
|
+
// Report pinning failures to server
|
|
1102
|
+
class PinningFailureReporter : CertificatePinner.EventListener {
|
|
1103
|
+
fun onPinningFailure(
|
|
1104
|
+
hostname: String,
|
|
1105
|
+
certificateChain: List<Certificate>,
|
|
1106
|
+
expectedPins: List<String>
|
|
1107
|
+
) {
|
|
1108
|
+
// Send report via a secondary channel (different domain/pinning config)
|
|
1109
|
+
SecurityReportingService.report(
|
|
1110
|
+
PinningFailure(
|
|
1111
|
+
hostname = hostname,
|
|
1112
|
+
actualFingerprint = certificateChain.first().sha256(),
|
|
1113
|
+
expectedPins = expectedPins,
|
|
1114
|
+
timestamp = System.currentTimeMillis(),
|
|
1115
|
+
deviceInfo = DeviceInfo.collect()
|
|
1116
|
+
)
|
|
1117
|
+
)
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
### 8.2 Traffic Interception Response Playbook
|
|
1123
|
+
|
|
1124
|
+
1. **Detection**: Pinning failure alert or anomalous traffic pattern identified.
|
|
1125
|
+
2. **Triage**: Determine if the failure is due to certificate rotation (benign) or interception.
|
|
1126
|
+
3. **Containment**: If interception confirmed, force re-authentication for affected sessions.
|
|
1127
|
+
4. **Investigation**: Analyze server logs for the scope of compromised sessions.
|
|
1128
|
+
5. **Remediation**: Rotate affected API keys/tokens. Issue forced app update if pinning
|
|
1129
|
+
configuration needs changing.
|
|
1130
|
+
6. **Communication**: Notify affected users per incident response policy and regulatory
|
|
1131
|
+
requirements.
|
|
1132
|
+
7. **Post-incident**: Review pinning configuration, add additional detection signals.
|
|
1133
|
+
|
|
1134
|
+
### 8.3 Common False Positives
|
|
1135
|
+
|
|
1136
|
+
- Corporate proxy/firewall performing TLS inspection (legitimate but triggers pinning failure).
|
|
1137
|
+
- Antivirus software on the device intercepting TLS (e.g., Kaspersky, Norton).
|
|
1138
|
+
- CDN or load balancer certificate rotation not reflected in pinning config.
|
|
1139
|
+
- Development/staging builds accidentally using production pinning config.
|
|
1140
|
+
- User traveling internationally with captive portal WiFi.
|
|
1141
|
+
|
|
1142
|
+
---
|
|
1143
|
+
|
|
1144
|
+
## 9. Compliance & Standards
|
|
1145
|
+
|
|
1146
|
+
### 9.1 OWASP MASVS-NETWORK
|
|
1147
|
+
|
|
1148
|
+
The OWASP Mobile Application Security Verification Standard (MASVS) defines the
|
|
1149
|
+
MASVS-NETWORK control group for secure network communication (data-in-transit).
|
|
1150
|
+
|
|
1151
|
+
**Key requirements:**
|
|
1152
|
+
- **MASVS-NETWORK-1**: The app secures all network traffic according to current best
|
|
1153
|
+
practices. TLS is used for all connections. No cleartext HTTP traffic.
|
|
1154
|
+
- **MASVS-NETWORK-2**: The app performs identity pinning for its remote endpoints. Certificate
|
|
1155
|
+
or public key pinning is implemented and enforced.
|
|
1156
|
+
|
|
1157
|
+
**Testing guidance (MASTG):**
|
|
1158
|
+
- MASTG-TEST-0019: Testing Data Encryption on the Network
|
|
1159
|
+
- MASTG-TEST-0020: Testing the TLS Settings
|
|
1160
|
+
- MASTG-TEST-0021: Testing Endpoint Identity Verification
|
|
1161
|
+
- MASTG-TEST-0022: Testing Custom Certificate Stores and Certificate Pinning
|
|
1162
|
+
|
|
1163
|
+
### 9.2 OWASP Mobile Top 10 (2024)
|
|
1164
|
+
|
|
1165
|
+
**M5: Insecure Communication** covers:
|
|
1166
|
+
- Failure to use TLS for all network traffic.
|
|
1167
|
+
- Use of deprecated TLS versions or weak cipher suites.
|
|
1168
|
+
- Failure to validate server certificates.
|
|
1169
|
+
- Missing certificate pinning.
|
|
1170
|
+
- Cleartext fallback on TLS failure.
|
|
1171
|
+
|
|
1172
|
+
This risk was previously ranked M3 in the 2016 list and moved to M5 in the 2024 update,
|
|
1173
|
+
reflecting improved platform defaults (ATS, NSC) but continued developer misconfigurations.
|
|
1174
|
+
|
|
1175
|
+
### 9.3 PCI DSS v4.0.1 (Mobile Requirements)
|
|
1176
|
+
|
|
1177
|
+
Released June 2024, PCI DSS v4.0.1 includes specific mobile requirements:
|
|
1178
|
+
|
|
1179
|
+
- **Requirement 4**: Protect cardholder data with strong cryptography during transmission
|
|
1180
|
+
over open, public networks. TLS 1.2 minimum, TLS 1.3 recommended.
|
|
1181
|
+
- **Requirement 6**: Develop and maintain secure systems and software. Includes secure coding
|
|
1182
|
+
practices, vulnerability management, and code review for mobile apps.
|
|
1183
|
+
- **Requirement 8**: Identify users and authenticate access. MFA is now mandatory for all
|
|
1184
|
+
access to cardholder data.
|
|
1185
|
+
|
|
1186
|
+
**Mobile-specific guidance:**
|
|
1187
|
+
- All payment API calls must use TLS 1.2+ with certificate pinning.
|
|
1188
|
+
- Tokenization (Stripe, Braintree) or wallet payments (Apple Pay/Google Pay) reduce PCI scope
|
|
1189
|
+
by ensuring the app never handles raw card data.
|
|
1190
|
+
- Network segmentation applies to mobile backend APIs handling cardholder data.
|
|
1191
|
+
|
|
1192
|
+
### 9.4 NIST SP 800-163 (Vetting Mobile Applications)
|
|
1193
|
+
|
|
1194
|
+
Provides guidelines for vetting the security of mobile applications, including:
|
|
1195
|
+
- Network communication analysis.
|
|
1196
|
+
- TLS implementation verification.
|
|
1197
|
+
- Data leakage assessment through network channels.
|
|
1198
|
+
|
|
1199
|
+
### 9.5 CISA Encrypted DNS Implementation Guidance (2024)
|
|
1200
|
+
|
|
1201
|
+
CISA published guidance on encrypted DNS (DoH/DoT) implementation in May 2024, recommending:
|
|
1202
|
+
- Organizations evaluate encrypted DNS for mobile fleet management.
|
|
1203
|
+
- Balance between privacy (DoH) and network visibility (enterprise monitoring).
|
|
1204
|
+
- Use trusted resolvers with DNSSEC validation.
|
|
1205
|
+
|
|
1206
|
+
---
|
|
1207
|
+
|
|
1208
|
+
## 10. Code Examples
|
|
1209
|
+
|
|
1210
|
+
### 10.1 Complete Certificate Pinning -- Swift (iOS)
|
|
1211
|
+
|
|
1212
|
+
```swift
|
|
1213
|
+
import Foundation
|
|
1214
|
+
import CryptoKit
|
|
1215
|
+
|
|
1216
|
+
/// Production-ready certificate pinning delegate for URLSession.
|
|
1217
|
+
/// Pins SPKI hashes to prevent MITM even with compromised CAs.
|
|
1218
|
+
final class SecureNetworkDelegate: NSObject, URLSessionDelegate {
|
|
1219
|
+
|
|
1220
|
+
struct PinConfiguration {
|
|
1221
|
+
let domain: String
|
|
1222
|
+
let spkiHashes: Set<String> // Base64-encoded SHA-256 of SPKI
|
|
1223
|
+
let includeSubdomains: Bool
|
|
1224
|
+
let reportURI: URL?
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
private let pins: [PinConfiguration]
|
|
1228
|
+
|
|
1229
|
+
init(pins: [PinConfiguration]) {
|
|
1230
|
+
self.pins = pins
|
|
1231
|
+
super.init()
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
func urlSession(
|
|
1235
|
+
_ session: URLSession,
|
|
1236
|
+
didReceive challenge: URLAuthenticationChallenge,
|
|
1237
|
+
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
|
1238
|
+
) {
|
|
1239
|
+
guard challenge.protectionSpace.authenticationMethod ==
|
|
1240
|
+
NSURLAuthenticationMethodServerTrust,
|
|
1241
|
+
let serverTrust = challenge.protectionSpace.serverTrust else {
|
|
1242
|
+
completionHandler(.cancelAuthenticationChallenge, nil)
|
|
1243
|
+
return
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
let host = challenge.protectionSpace.host
|
|
1247
|
+
|
|
1248
|
+
// Find matching pin configuration
|
|
1249
|
+
guard let pinConfig = pins.first(where: { config in
|
|
1250
|
+
if config.includeSubdomains {
|
|
1251
|
+
return host == config.domain || host.hasSuffix(".\(config.domain)")
|
|
1252
|
+
}
|
|
1253
|
+
return host == config.domain
|
|
1254
|
+
}) else {
|
|
1255
|
+
// No pin configured for this domain -- use default validation
|
|
1256
|
+
completionHandler(.performDefaultHandling, nil)
|
|
1257
|
+
return
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// Perform standard trust evaluation first
|
|
1261
|
+
let policy = SecPolicyCreateSSL(true, host as CFString)
|
|
1262
|
+
SecTrustSetPolicies(serverTrust, policy)
|
|
1263
|
+
|
|
1264
|
+
var error: CFError?
|
|
1265
|
+
guard SecTrustEvaluateWithError(serverTrust, &error) else {
|
|
1266
|
+
completionHandler(.cancelAuthenticationChallenge, nil)
|
|
1267
|
+
return
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// Verify SPKI hash against pins
|
|
1271
|
+
guard let certChain = SecTrustCopyCertificateChain(serverTrust) as? [SecCertificate] else {
|
|
1272
|
+
completionHandler(.cancelAuthenticationChallenge, nil)
|
|
1273
|
+
return
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
for cert in certChain {
|
|
1277
|
+
if let publicKey = SecCertificateCopyKey(cert),
|
|
1278
|
+
let keyData = SecKeyCopyExternalRepresentation(publicKey, nil) as Data? {
|
|
1279
|
+
let hash = SHA256.hash(data: keyData)
|
|
1280
|
+
let hashString = Data(hash).base64EncodedString()
|
|
1281
|
+
|
|
1282
|
+
if pinConfig.spkiHashes.contains(hashString) {
|
|
1283
|
+
completionHandler(.useCredential, URLCredential(trust: serverTrust))
|
|
1284
|
+
return
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// Pin verification failed -- report and reject
|
|
1290
|
+
reportPinningFailure(host: host, reportURI: pinConfig.reportURI)
|
|
1291
|
+
completionHandler(.cancelAuthenticationChallenge, nil)
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
private func reportPinningFailure(host: String, reportURI: URL?) {
|
|
1295
|
+
guard let reportURI = reportURI else { return }
|
|
1296
|
+
// Send failure report via a separate, independently pinned channel
|
|
1297
|
+
let report: [String: Any] = [
|
|
1298
|
+
"hostname": host,
|
|
1299
|
+
"timestamp": ISO8601DateFormatter().string(from: Date()),
|
|
1300
|
+
"app_version": Bundle.main.infoDictionary?["CFBundleShortVersionString"] ?? ""
|
|
1301
|
+
]
|
|
1302
|
+
// Fire-and-forget report (use a separate URLSession without pinning to this domain)
|
|
1303
|
+
var request = URLRequest(url: reportURI)
|
|
1304
|
+
request.httpMethod = "POST"
|
|
1305
|
+
request.httpBody = try? JSONSerialization.data(withJSONObject: report)
|
|
1306
|
+
URLSession.shared.dataTask(with: request).resume()
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
### 10.2 Complete Certificate Pinning -- Kotlin (Android)
|
|
1312
|
+
|
|
1313
|
+
```kotlin
|
|
1314
|
+
import okhttp3.*
|
|
1315
|
+
import java.security.MessageDigest
|
|
1316
|
+
import java.security.cert.X509Certificate
|
|
1317
|
+
import javax.net.ssl.*
|
|
1318
|
+
|
|
1319
|
+
/**
|
|
1320
|
+
* Production-ready OkHttp client with certificate pinning,
|
|
1321
|
+
* TLS enforcement, and security monitoring.
|
|
1322
|
+
*/
|
|
1323
|
+
object SecureNetworkClient {
|
|
1324
|
+
|
|
1325
|
+
private val PINS = mapOf(
|
|
1326
|
+
"api.example.com" to listOf(
|
|
1327
|
+
"sha256/k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=",
|
|
1328
|
+
"sha256/VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8="
|
|
1329
|
+
)
|
|
1330
|
+
)
|
|
1331
|
+
|
|
1332
|
+
fun create(): OkHttpClient {
|
|
1333
|
+
val pinnerBuilder = CertificatePinner.Builder()
|
|
1334
|
+
PINS.forEach { (domain, pins) ->
|
|
1335
|
+
pinnerBuilder.add(domain, *pins.toTypedArray())
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
return OkHttpClient.Builder()
|
|
1339
|
+
.certificatePinner(pinnerBuilder.build())
|
|
1340
|
+
.connectionSpecs(listOf(
|
|
1341
|
+
ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
|
1342
|
+
.tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_3)
|
|
1343
|
+
.cipherSuites(
|
|
1344
|
+
CipherSuite.TLS_AES_128_GCM_SHA256,
|
|
1345
|
+
CipherSuite.TLS_AES_256_GCM_SHA384,
|
|
1346
|
+
CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
|
|
1347
|
+
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
1348
|
+
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
|
1349
|
+
)
|
|
1350
|
+
.build()
|
|
1351
|
+
))
|
|
1352
|
+
.addInterceptor(HttpsEnforcementInterceptor())
|
|
1353
|
+
.addInterceptor(SecurityHeaderInterceptor())
|
|
1354
|
+
.build()
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
/** Rejects any non-HTTPS request at the interceptor level. */
|
|
1358
|
+
private class HttpsEnforcementInterceptor : Interceptor {
|
|
1359
|
+
override fun intercept(chain: Interceptor.Chain): Response {
|
|
1360
|
+
val request = chain.request()
|
|
1361
|
+
check(request.url.scheme == "https") {
|
|
1362
|
+
"SECURITY: Cleartext HTTP request blocked: ${request.url}"
|
|
1363
|
+
}
|
|
1364
|
+
return chain.proceed(request)
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/** Adds security headers to all outgoing requests. */
|
|
1369
|
+
private class SecurityHeaderInterceptor : Interceptor {
|
|
1370
|
+
override fun intercept(chain: Interceptor.Chain): Response {
|
|
1371
|
+
val request = chain.request().newBuilder()
|
|
1372
|
+
.header("X-Content-Type-Options", "nosniff")
|
|
1373
|
+
.header("X-Request-Id", java.util.UUID.randomUUID().toString())
|
|
1374
|
+
.build()
|
|
1375
|
+
return chain.proceed(request)
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
```
|
|
1380
|
+
|
|
1381
|
+
### 10.3 Complete Certificate Pinning -- Dart (Flutter)
|
|
1382
|
+
|
|
1383
|
+
```dart
|
|
1384
|
+
import 'dart:io';
|
|
1385
|
+
import 'dart:convert';
|
|
1386
|
+
import 'package:flutter/services.dart';
|
|
1387
|
+
import 'package:crypto/crypto.dart';
|
|
1388
|
+
|
|
1389
|
+
/// Production-ready HTTP client with SPKI certificate pinning for Flutter.
|
|
1390
|
+
class SecureApiClient {
|
|
1391
|
+
static const _pinnedHashes = {
|
|
1392
|
+
'api.example.com': [
|
|
1393
|
+
'k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=', // current
|
|
1394
|
+
'VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=', // backup
|
|
1395
|
+
],
|
|
1396
|
+
};
|
|
1397
|
+
|
|
1398
|
+
late final HttpClient _client;
|
|
1399
|
+
|
|
1400
|
+
Future<void> initialize() async {
|
|
1401
|
+
final context = SecurityContext(withTrustedRoots: true);
|
|
1402
|
+
|
|
1403
|
+
_client = HttpClient(context: context)
|
|
1404
|
+
..badCertificateCallback = _validateCertificate;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
bool _validateCertificate(X509Certificate cert, String host, int port) {
|
|
1408
|
+
// Reject any certificate not matching our pins
|
|
1409
|
+
final domainPins = _pinnedHashes[host];
|
|
1410
|
+
if (domainPins == null) return false;
|
|
1411
|
+
|
|
1412
|
+
final certBytes = cert.der;
|
|
1413
|
+
final digest = sha256.convert(certBytes);
|
|
1414
|
+
final hashString = base64.encode(digest.bytes);
|
|
1415
|
+
|
|
1416
|
+
return domainPins.contains(hashString);
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
Future<Map<String, dynamic>> get(String path) async {
|
|
1420
|
+
final uri = Uri.https('api.example.com', path);
|
|
1421
|
+
final request = await _client.getUrl(uri);
|
|
1422
|
+
request.headers.set('Accept', 'application/json');
|
|
1423
|
+
|
|
1424
|
+
final response = await request.close();
|
|
1425
|
+
final body = await response.transform(utf8.decoder).join();
|
|
1426
|
+
return jsonDecode(body) as Map<String, dynamic>;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
void dispose() {
|
|
1430
|
+
_client.close();
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
```
|
|
1434
|
+
|
|
1435
|
+
### 10.4 Network Security Config -- Complete XML (Android)
|
|
1436
|
+
|
|
1437
|
+
```xml
|
|
1438
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
1439
|
+
<!--
|
|
1440
|
+
Production network security configuration.
|
|
1441
|
+
Enforces HTTPS, certificate pinning, and CT compliance.
|
|
1442
|
+
Reference: https://developer.android.com/privacy-and-security/security-config
|
|
1443
|
+
-->
|
|
1444
|
+
<network-security-config>
|
|
1445
|
+
|
|
1446
|
+
<!-- Global: block all cleartext traffic -->
|
|
1447
|
+
<base-config cleartextTrafficPermitted="false">
|
|
1448
|
+
<trust-anchors>
|
|
1449
|
+
<certificates src="system" />
|
|
1450
|
+
</trust-anchors>
|
|
1451
|
+
</base-config>
|
|
1452
|
+
|
|
1453
|
+
<!-- Primary API domain with certificate pinning -->
|
|
1454
|
+
<domain-config>
|
|
1455
|
+
<domain includeSubdomains="true">api.example.com</domain>
|
|
1456
|
+
<pin-set expiration="2025-12-31">
|
|
1457
|
+
<pin digest="SHA-256">k1LOS/oeay2ibJkR7mFhHGTCXMxrjKgmbn2OhQBYz9E=</pin>
|
|
1458
|
+
<pin digest="SHA-256">VjLZe/p3W/PJnd6lL8JVNBCGQBZynFLdZSTIqcO0SJ8=</pin>
|
|
1459
|
+
</pin-set>
|
|
1460
|
+
<trust-anchors>
|
|
1461
|
+
<certificates src="system" />
|
|
1462
|
+
</trust-anchors>
|
|
1463
|
+
</domain-config>
|
|
1464
|
+
|
|
1465
|
+
<!-- CDN domain (pinning optional but cleartext still blocked) -->
|
|
1466
|
+
<domain-config>
|
|
1467
|
+
<domain includeSubdomains="true">cdn.example.com</domain>
|
|
1468
|
+
<trust-anchors>
|
|
1469
|
+
<certificates src="system" />
|
|
1470
|
+
</trust-anchors>
|
|
1471
|
+
</domain-config>
|
|
1472
|
+
|
|
1473
|
+
<!-- Debug overrides: allow user-installed CAs for proxy testing -->
|
|
1474
|
+
<debug-overrides>
|
|
1475
|
+
<trust-anchors>
|
|
1476
|
+
<certificates src="user" />
|
|
1477
|
+
<certificates src="system" />
|
|
1478
|
+
</trust-anchors>
|
|
1479
|
+
</debug-overrides>
|
|
1480
|
+
|
|
1481
|
+
</network-security-config>
|
|
1482
|
+
```
|
|
1483
|
+
|
|
1484
|
+
### 10.5 Insecure vs. Secure Comparison Table
|
|
1485
|
+
|
|
1486
|
+
| Pattern | Insecure | Secure |
|
|
1487
|
+
|---------|----------|--------|
|
|
1488
|
+
| Protocol | `http://api.example.com` | `https://api.example.com` |
|
|
1489
|
+
| TLS version | `TLSv10`, `TLSv11` | `TLSv12`, `TLSv13` |
|
|
1490
|
+
| Cert validation | `trustAllCerts`, `ALLOW_ALL` | System trust + SPKI pinning |
|
|
1491
|
+
| Hostname check | `hostnameVerifier { _, _ -> true }` | Default OkHostnameVerifier |
|
|
1492
|
+
| API keys | Hardcoded in source | Fetched from server, stored in Keystore/Keychain |
|
|
1493
|
+
| Sensitive params | In URL query string | In Authorization header or POST body |
|
|
1494
|
+
| WebSocket | `ws://` | `wss://` with pinning |
|
|
1495
|
+
| DNS | System resolver (cleartext) | DNS-over-HTTPS |
|
|
1496
|
+
| Error handling | Show TLS errors to user | Generic message, server-side logging |
|
|
1497
|
+
| Debug code | `if (DEBUG) trustAll()` left in release | Build-variant configs, no debug code in release |
|
|
1498
|
+
|
|
1499
|
+
---
|
|
1500
|
+
|
|
1501
|
+
## References
|
|
1502
|
+
|
|
1503
|
+
- [OWASP Mobile Top 10 (2024)](https://owasp.org/www-project-mobile-top-10/)
|
|
1504
|
+
- [OWASP MASVS - Network Requirements](https://mas.owasp.org/MASVS/)
|
|
1505
|
+
- [OWASP MASTG - Certificate Pinning](https://mas.owasp.org/MASTG/knowledge/android/MASVS-NETWORK/MASTG-KNOW-0015/)
|
|
1506
|
+
- [OWASP MASTG - Bypassing Certificate Pinning](https://mas.owasp.org/MASTG/techniques/android/MASTG-TECH-0012/)
|
|
1507
|
+
- [Android Network Security Configuration](https://developer.android.com/privacy-and-security/security-config)
|
|
1508
|
+
- [Android Certificate Transparency Policy](https://developer.android.com/privacy-and-security/certificate-transparency-policy)
|
|
1509
|
+
- [Apple App Transport Security](https://developer.apple.com/news/?id=jxky8h89)
|
|
1510
|
+
- [Apple Certificate Transparency Policy](https://support.apple.com/en-us/103214)
|
|
1511
|
+
- [Apple Identity Pinning Guide](https://developer.apple.com/news/?id=g9ejcf8y)
|
|
1512
|
+
- [OkHttp HTTPS Configuration](https://square.github.io/okhttp/features/https/)
|
|
1513
|
+
- [PCI DSS v4.0.1 Requirements](https://www.pcisecuritystandards.org/)
|
|
1514
|
+
- [CISA Encrypted DNS Implementation Guidance (2024)](https://www.cisa.gov/sites/default/files/2024-05/Encrypted%20DNS%20Implementation%20Guidance_508c.pdf)
|
|
1515
|
+
- [Zimperium - Mobile App Data Leakage Research](https://zimperium.com/blog/your-apps-are-leaking-the-hidden-data-risks-on-your-phone)
|
|
1516
|
+
- [NowSecure - Top Mobile App Security Breaches](https://www.nowsecure.com/)
|
|
1517
|
+
- [8kSec - SSL Pinning in Mobile Apps (2025)](https://8ksec.io/why-you-should-remove-ssl-pinning-from-your-mobile-apps-in-2025/)
|
|
1518
|
+
- [Verizon 2025 Data Breach Investigations Report](https://www.verizon.com/business/resources/reports/dbir/)
|
|
1519
|
+
- [Banking Apps MITM Vulnerability (Threatpost)](https://threatpost.com/banking-apps-found-vulnerable-to-mitm-attacks/129105/)
|
|
1520
|
+
- [Unit 42 - Android Apps Data Leakage](https://unit42.paloaltonetworks.com/android-apps-data-leakage/)
|