Liste de contrôle de sécurité pour les applications Flutter
Phase 0 : Gouvernance, environnement et CI/CD
Outillage et versions
- Maintenir à jour Flutter, le SDK Dart, Android Studio/Xcode, ainsi que l'ensemble des plugins et dépendances.
- Examiner les avis de sécurité pour les paquets Flutter et les SDK natifs avant chaque release.
Appliquer les contrôles CI (CI gates)
- Sur chaque PR, exécuter :
-
dart analyze -
flutter test --coverage - Android/Gradle lint
- Les vérifications de build iOS
- Les audits des dépendances
- Faire échouer les builds en cas d'erreurs d'analyseur et d'avertissements configurés comme erreurs.
- Imposer zéro erreur de lint sur les branches de release.
Établir des contrôles de sécurité (security gates)
- Exécuter des scans SAST/SCA/DAST mobiles sur chaque PR et avant les releases.
- Bloquer les builds en cas de résultats de sévérité Élevée/Critique (High/Critical).
- Intégrer les scans directement dans le pipeline CI/CD afin que les vulnérabilités Élevées/Critiques fassent échouer le pipeline.
Gestion des secrets
- S'assurer de l'absence totale de secrets dans :
- Le code source Dart
- Le code natif
-
AndroidManifest.xml -
Info.plist - Les ressources (assets)
- Les journaux (logs)
- Utiliser des variables d'environnement, des coffres de secrets CI et/ou des gestionnaires de secrets.
- Expurger les secrets dans les outils d'analytics et de journalisation.
- Effectuer une rotation régulière des clés d'API/jetons et dès qu'une fuite est suspectée.
Preuves et traçabilité
- Produire et archiver pour chaque artefact :
- Les rapports de scan
- Les SBOMs
- Les journaux de build
- Les rapports de tests
- Les notes de version (release notes)
Phase 1 : Modélisation des menaces, classification des données et inventaire
- Classifier les types de données (PII, identifiants, jetons, données de paiement, données de santé).
- Documenter où chaque type de donnée est collecté, traité, stocké et transmis dans :
- Le code de l'application Flutter
- Les couches natives
- Identifier les frontières de confiance (trust boundaries) :
- Le code de l'application Flutter
- Les canaux de plateforme natifs (platform channels Android/iOS)
- Le stockage de l'appareil
- La WebView / le navigateur
- Les API backend
- Les services tiers
- Inventorier l'ensemble des paquets Dart, plugins et SDK natifs.
- Privilégier les dépendances bien maintenues, signées et appliquant le principe du moindre privilège.
- Minimiser le nombre total et le périmètre des dépendances.
- Définir des critères d'acceptation de sécurité par classe de risque (ex. : « Aucune donnée sensible au repos en clair », « Tout le trafic d'authentification épinglé », « Aucun journal de débogage en release »).
Phase 2 : Durcissement du build et de la configuration (Flutter + Android + iOS)
Builds de release Flutter
- Compiler avec obfusquation et séparation des symboles de débogage pour Android :
-
flutter build appbundle --release --obfuscate --split-debug-info=build/symbols - Compiler avec obfusquation et séparation des symboles de débogage pour iOS :
-
flutter build ipa --release --obfuscate --split-debug-info=build/symbols - Stocker
build/symbolsde manière sécurisée côté serveur. - Ne jamais inclure les symboles ou les fichiers de mappage dans le bundle de l'application.
Hygiène de journalisation (logging)
- Protéger les journaux derrière
kReleaseModeou un équivalent. - Supprimer
print/debugPrint/ la journalisation verbeuse des chemins de code de production. - Ajouter des vérifications CI pour faire échouer les builds lorsque des journaux de débogage apparaissent dans du code hors tests sur les branches de release.
Android (Gradle + Manifest)
- Activer R8/ProGuard et la réduction des ressources (resource shrinking) pour la release :
-
minifyEnabled true -
shrinkResources true - Utiliser des règles ProGuard optimisées.
- Durcir
AndroidManifest.xml: -
android:debuggable="false"en release. -
android:allowBackup="false"sauf en cas de conception sécurisée des sauvegardes. -
android:usesCleartextTraffic="false"; aucun repli HTTP en production. - Définir explicitement
android:exportedsur les composants ; éviter d'exporter sans garde de permissions stricte. - Configurer la sécurité réseau (Network Security Config) :
- Désactiver le trafic en clair globalement.
- Définir des configurations par domaine.
- Si l'épinglage (pinning) est utilisé, définir des ensembles d'épingles avec des épingles de secours (backup pins).
- Signature et intégrité :
- Utiliser Play App Signing le cas échéant.
- Protéger les magasins de clés (keystores).
- Activer la Play Integrity API et intégrer ses signaux aux décisions de risque du backend.
iOS (Xcode + Info.plist au sein du projet Flutter)
- App Transport Security (ATS) :
-
NSAllowsArbitraryLoads = false. - Utiliser des
NSExceptionDomainsstricts uniquement pour des exceptions nécessaires et limitées dans le temps. - Paramètres de build de release :
- Éliminer les symboles (strip symbols).
- Activer l'élimination du code mort (dead code stripping).
- Activer l'optimisation globale du module (whole-module optimization).
- S'assurer de l'absence d'indicateurs
DEBUGou de bibliothèques de test dans les builds de release. - Valeurs par défaut du Keychain pour le stockage natif/plugin :
- Privilégier les classes
ThisDeviceOnlylorsque cela est possible. - Masquer les instantanés (snapshots) lors du passage en arrière-plan (via du code natif ou des plugins Flutter) afin que le sélecteur d'applications n'affiche jamais de données sensibles.
Phase 3 : Sécurité réseau et TLS/épinglage (pinning)
Application stricte de HTTPS/TLS
- S'assurer que tout le trafic d'API utilise HTTPS/TLS 1.2+.
- Rejeter les certificats invalides, les certificats auto-signés (s'ils ne sont pas explicitement approuvés) et les points de terminaison dont le nom d'hôte ne correspond pas.
- Configurer des délais d'attente (timeouts) raisonnables.
- Implémenter des réessais avec gigue (retry with jitter) le cas échéant.
- Toujours adopter un comportement de fermeture par défaut (fail closed) en cas d'erreur TLS (aucun déclassement vers HTTP).
Épinglage de certificat (certificate pinning)
- Pour les domaines critiques, implémenter l'épinglage de certificat ou de clé publique SPKI SHA-256 dans :
- Le client HTTP utilisé par Flutter.
- Tout réseau natif utilisé par les plugins.
- Maintenir au moins une épingle de secours (backup pin) par hôte.
- Concevoir et tester des scénarios de rotation d'épingles.
- Valider le comportement de l'épinglage face à :
- Des tentatives de MITM.
- Des certificats expirés.
- Des autorités de certification (CA) non approuvées.
- Journaliser les échecs d'épinglage et remonter la télémétrie.
Sécurité côté serveur
- Imposer HSTS sur les points de terminaison backend.
- Utiliser des suites de chiffrement robustes et des versions de protocole modernes.
- Utiliser des cookies sécurisés, HttpOnly et SameSite pour les points de terminaison web consultés via WebView ou des navigateurs intégrés.
- Éviter les jetons porteurs (bearer tokens) à longue durée de vie sur le client.
Phase 4 : Stockage local et gestion des secrets
Secrets et jetons
- Ne jamais stocker de secrets/jetons dans :
-
SharedPreferences - Les fichiers
plist - SQLite non chiffré
- Des fichiers en texte clair depuis Dart
- Ne pas intégrer de secrets dans :
- Les valeurs
const - Les ressources (assets)
- Le code généré
Stockage sécurisé
- Utiliser un stockage sécurisé lié aux magasins de clés de la plateforme pour les jetons et les clés (ex. : Android Keystore, Keychain iOS via des plugins Flutter).
- Lorsque l'expérience utilisateur le permet, conditionner le déchiffrement/l'utilisation des clés à haut risque à la biométrie ou au code de déverrouillage du système.
- Privilégier les clés liées à l'appareil (
ThisDeviceOnly/ adossées au matériel) pour les jetons de grande valeur.
Stockage chiffré (fichiers/bases de données)
- Utiliser SQLite chiffré ou un chiffrement de fichiers équivalent pour les enregistrements sensibles.
- S'assurer que les couches de cache (ex. : cache HTTP, persistance locale) ne stockent pas de PII ou de secrets en clair.
Cycle de vie des données
- Effacer :
- Les caches
- Les entrées du stockage sécurisé
- Les objets sensibles en mémoire
lors de la déconnexion et de la suppression du compte. - Nettoyer les données de WebView ou du navigateur in-app après les flux d'authentification ou les sessions à haut risque.
- Configurer les règles de sauvegarde Android/iOS pour empêcher la sauvegarde de données applicatives sensibles sous forme non chiffrée.
Phase 5 : Protections de la vie privée (interface, presse-papiers, captures d'écran)
- Masquer les écrans Flutter sensibles lorsque l'application est en arrière-plan ou dans le sélecteur de tâches :
-
FLAG_SECUREsur Android. - Masquage d'instantané (snapshot masking) sur iOS.
- Pour les vues extrêmement sensibles (ex. : numéros de carte complets, secrets), utiliser un modèle d'« écran sécurisé » dédié avec :
- Masquage renforcé.
- Aucune prise en charge des captures d'écran ou des enregistrements d'écran.
- Éviter de lire le presse-papiers au lancement de l'application.
- Ne jamais placer de mots de passe, de jetons ou de liens de réinitialisation dans le presse-papiers.
- S'assurer que les captures d'écran ou exportations intégrées à l'application omettent les secrets/PII, sauf si cela est explicitement requis et clairement communiqué à l'utilisateur.
Phase 6 : Authentification, autorisation et session
Flux d'authentification
- Utiliser OAuth2/OIDC avec PKCE pour les clients Flutter publics.
- Ne pas intégrer de secrets client (client secrets) dans l'application.
- Préférer le navigateur système / les flux d'authentification de la plateforme :
- Chrome Custom Tabs sur Android.
-
SFSafariViewController/ASWebAuthenticationSessionsur iOS via des plugins. - Éviter la connexion au sein d'une WebView lorsque cela est possible.
Jetons
- Utiliser des jetons d'accès (access tokens) à courte durée de vie.
- Stocker les jetons d'actualisation (refresh tokens) uniquement dans un stockage sécurisé lié aux magasins de clés de la plateforme.
- Effectuer une rotation régulière des jetons.
- Invalider les jetons lors de :
- La déconnexion.
- Un changement d'appareil.
- Comportements suspects.
- Envisager la liaison à l'appareil (device binding) et des contrôles basés sur le risque pour les actions hautement sensibles, à l'aide des signaux d'appareil d'Android et d'iOS.
Autorisation
- Appliquer le contrôle d'accès sur le serveur.
- Ne pas se fier à la logique Dart/UI pour protéger les ressources.
- Tester l'absence de :
- IDOR/BOLA.
- Assignation de masse (mass assignment).
- Élévation de privilèges verticale et horizontale
sur l'ensemble des points de terminaison d'API utilisés par l'application Flutter.
Phase 7 : Durcissement des WebViews et flux basés sur le navigateur
Modèle recommandé
- Utiliser le navigateur système / les vues web sécurisées fournies par la plateforme pour l'authentification et les paiements lorsque cela est possible :
- Custom Tabs.
-
SFSafariViewController.
Si une WebView est requise (WebView Flutter ou native)
- Désactiver JavaScript par défaut.
- N'activer JavaScript que si explicitement requis, puis en limiter les capacités.
- Restreindre la navigation à une liste d'autorisation (allowlist) d'hôtes et de schémas de confiance.
- Bloquer
file://,javascript:et les autres URL dangereuses. - Désactiver le débogage de contenu web dans les builds de release sur Android et iOS.
- Effacer les cookies, le cache et le stockage de la WebView après les sessions sensibles (authentification, paiements, modification de PII).
- S'assurer que le contenu web interne (first-party) :
- Applique une CSP.
- Utilise exclusivement HTTPS.
- Ne comporte aucun contenu mixte (mixed content).
Phase 8 : Communication entre applications, liens profonds et canaux de plateforme
Liens profonds (deep links) et flux inter-applications
- Privilégier les Android App Links et les Universal Links iOS pour les liens profonds.
- Valider l'origine des liens avant d'agir.
- Valider et assainir les paramètres des liens avant toute action.
- Éviter les schémas d'URL personnalisés non sécurisés.
- Si des schémas personnalisés sont utilisés :
- Choisir des schémas uniques.
- Valider de manière robuste tous les paramètres et redirections.
Canaux de plateforme (MethodChannel / EventChannel)
- Traiter toutes les données transitant de Flutter vers le natif et inversement comme non fiables jusqu'à validation.
- Valider les noms de méthodes et les paramètres du côté natif.
- Éviter d'exposer des API natives puissantes directement via les canaux.
- Ne jamais transmettre de données brutes non fiables provenant de Flutter directement à des appels natifs privilégiés (système de fichiers, paramètres système, télécoms, etc.) sans validation ni assainissement.
- Tester par fuzzing les entrées des canaux de plateforme pendant les tests.
- Journaliser et gérer de manière sécurisée les appels de méthodes inattendus ou les données malformées.
Phase 9 : Rétro-ingénierie et résistance à la falsification (tamper resilience)
Réduire les fuites statiques
- Obfusquer le code Dart.
- Activer R8/ProGuard/la réduction des ressources pour Android.
- Retirer les symboles et les informations de débogage des binaires distribués sur les deux plateformes.
- Supprimer les journaux verbeux, les menus de débogage, les points de terminaison de test, les feature flags masqués et les portes dérobées dans les builds de release.
- Éviter d'intégrer des secrets ou de la logique métier sensible sous une forme facilement extractible (ex. : chaînes en clair dans les assets).
Vérifications de l'environnement
- Ajouter une détection de root/jailbreak/hooking/débogeur sur Android et iOS (via des plugins ou du code natif).
- Journaliser les signaux détectés pour la surveillance de la sécurité.
- Réagir proportionnellement :
- Dégrader les fonctionnalités.
- Ajouter une vérification supplémentaire.
- Bloquer les opérations à haut risque
au lieu de poursuivre silencieusement comme si de rien n'était.
Tests de falsification et intégrité
- Valider que les applications Flutter réempaquetées ou resignées sont détectées via des vérifications d'intégrité ou une attestation côté serveur :
- Play Integrity (Android).
- Contrôles d'appareil sur iOS (DeviceCheck / App Attest).
- Traiter les contrôles anti-falsification côté client comme des signaux transmis au backend.
- Ne jamais utiliser les contrôles anti-falsification côté client comme unique contrôle de sécurité.
Phase 10 : Cryptographie et aléa
- Utiliser des bibliothèques cryptographiques reconnues et approuvées par la plateforme (ex. : plugins encapsulant Android Keystore/iOS Keychain ou bibliothèques cryptographiques rigoureusement auditées).
- Ne pas implémenter d'algorithmes cryptographiques personnalisés en Dart.
- Pour le chiffrement, utiliser des modes AEAD modernes :
- AES-GCM.
- ChaCha20-Poly1305.
- Pour les KDFs, utiliser :
- PBKDF2.
- HKDF
avec des paramètres appropriés et des sels uniques par valeur. - Générer les clés, les IV et les nonces à l'aide d'un générateur d'aléa sécurisé (SecureRandom ou générateurs de nombres aléatoires de la plateforme via des plugins).
- Ne jamais réutiliser d'IV/nonces.
- Conserver les clés cryptographiques dans un stockage protégé par Keystore/Keychain ou chiffré au repos, et non en mémoire ou dans la configuration plus longtemps que nécessaire.
Phase 11 : Permissions, notifications et identifiants
Permissions
- Demander le strict minimum de permissions nécessaires.
- Ne demander les permissions qu'au moment opportun de leur utilisation (point-of-use).
- Fournir une expérience utilisateur (UX) claire expliquant pourquoi chaque permission est requise.
- Implémenter des parcours de refus et de révocation sans plantage (fonctionnalités limitées au lieu de crashs ou d'invites répétées en boucle).
Confidentialité et identifiants
- N'utiliser les identifiants publicitaires et d'analytics (ex. : GAID/IDFA) que conformément aux politiques des plateformes, avec des flux de consentement appropriés.
- Éviter de mettre en place une empreinte persistante inter-applications (fingerprinting) avec :
- Des identifiants matériels.
- Des adresses MAC.
- D'autres identifiants interdits.
Notifications
- Minimiser le contenu sensible dans les notifications push et locales.
- Utiliser des titres et descriptions génériques pour les notifications affichées sur l'écran de verrouillage.
- Permettre aux utilisateurs de configurer les catégories et la sensibilité des notifications.
- Ne jamais inclure de secrets ou de PII complètes dans les charges utiles (payloads) de notification.
Phase 12 : Journalisation, analytics et rapports de crash
- Standardiser sur une journalisation structurée.
- Désactiver la journalisation verbeuse/de débogage dans les builds de release.
- Expurger les PII et les secrets des :
- Journaux
- Événements d'analytics
- Rapports de crash
- Privilégier l'agrégation et l'échantillonnage pour les analytics.
- Stocker les fichiers de symboles/mappage (Flutter split debug info, correspondances R8, dSYMs) de manière sécurisée côté serveur pour la désobfuscation des crashs.
- Ne jamais inclure les fichiers de symboles/mappage dans le bundle de l'application.
- Examiner régulièrement les événements d'analytics et les journaux pour détecter d'éventuelles données inattendues (champs sensibles, paramètres d'URL, en-têtes, payloads).
Phase 13 : Tests, DAST et vérification à l'exécution
Tests d'interception du trafic
- Vérifier que la validation TLS rejette :
- Les certificats invalides.
- Les certificats expirés.
- Les certificats auto-signés (sauf s'ils sont explicitement approuvés).
- Les non-concordances de nom d'hôte.
- Confirmer que l'épinglage de certificat (lorsqu'il est activé) bloque les outils d'interception MITM.
Inspection à l'exécution (runtime)
- Pendant les tests, inspecter :
- Le stockage de l'application (
SharedPreferences, fichiers, bases de données). - Le stockage WebView.
- Les journaux
à la recherche de secrets/PII. - Confirmer que le stockage sécurisé et le chiffrement sont correctement appliqués.
- Confirmer que le nettoyage lors de la déconnexion et de la suppression du compte est effectif.
Tests d'abus d'API
- Valider :
- Les limitations de débit (rate limits).
- Les protections contre le rejeu (replay protections).
- Les limites de pagination.
- La validation des entrées
pour toutes les API utilisées par l'application Flutter. - Vérifier que les messages d'erreur du serveur ne sont pas excessivement verbeux et ne font pas fuiter de détails d'implémentation.
Analyse dynamique et DAST
- Exécuter des outils DAST mobiles tout en parcourant les flux fondamentaux de Flutter (authentification, paiements, profil, paramètres).
- Utiliser le DAST pour révéler :
- Les problèmes de transport.
- Les problèmes de stockage.
- Les problèmes de WebView.
- Exporter les preuves pour le triage.
- Corriger les vulnérabilités découvertes et re-tester avant de promouvoir les builds.
Phase 14 : SBOM et preuves
SBOM et dépendances
- Générer et archiver des SBOMs pour :
- Flutter (
pubspec.lock). - Les modules natifs (Gradle/CocoaPods).
- Suivre les CVE et les avis de sécurité pour l'ensemble de vos paquets au fil du temps.
- Planifier des actualisations de dépendances dans le cadre de la préparation des releases.
Dossier de preuves (evidence bundle)
- Joindre à chaque dossier de release :
- Les rapports SAST/SCA/DAST.
- Les SBOMs.
- Les configurations de build (obfusquation, épinglage, ATS/networkSecurityConfig).
- Les rapports de tests (automatisés et manuels).
Phase 15 : Rapports et alignement sur les normes
Rapports
- Produire pour les applications Flutter :
- Résumé managérial (executive summary).
- Périmètre et méthodologie.
- Résultats détaillés avec PoC et captures d'écran.
- Évaluations des risques.
- Plans de remédiation.
- Résultats des retests.
Correspondance OWASP MASVS
- PLATFORM : Phases 2, 7–8, 11.
- STORAGE : Phases 3–4.
- CRYPTO : Phase 10.
- AUTH : Phase 6.
- NETWORK : Phase 5.
- CODE : Phases 2, 8, 12.
- RESILIENCE : Phase 9.
Référence rapide pour les praticiens
- Builds :
--obfuscate --split-debug-info, R8minifyEnabled true,shrinkResources true; aucun symbole de débogage dans les artefacts distribués. - Réseau : HTTPS uniquement ; épinglage de certificat/SPKI (avec épingles de secours) pour les API critiques ; vérifier l'échec des attaques MITM.
- Stockage : Stockage sécurisé pour les jetons ; base de données/fichiers chiffrés pour les données sensibles ; purge à la déconnexion ; prévention des sauvegardes sensibles.
- Auth : OIDC + PKCE ; jetons à courte durée de vie ; jetons de rafraîchissement dans un stockage sécurisé ; autorisation côté serveur ; tester l'absence d'IDOR/BOLA.
- WebView : Préférer le navigateur système pour l'authentification ; si une WebView est utilisée, désactiver JS par défaut, appliquer une allowlist de navigation, purger les données après les flux sensibles.
- Confidentialité : Masquer les instantanés d'arrière-plan via les indicateurs de plateforme ; éviter les secrets dans le presse-papiers ; permissions minimales avec une UX claire.
- Contrôles CI : Bloquer en cas de vulnérabilité Élevée/Critique en SAST/SCA ; exiger « zéro vulnérabilité Élevée » en DAST ; zéro erreur d'analyseur/linter pour la release.