Document de référence Bloc 2 — C2.2.3 du RNCP39583. Mapping des mesures de sécurité côté application Flutter face à l'OWASP Mobile Top 10 (2024) et aux principes OWASP web applicables.
| Risque | Couverture | Localisation |
|---|---|---|
| M1/A01 Mauvaise authentification et autorisation | ✅ | ApiClient + repository auth |
| M2/A02 Stockage des données peu sûr | ✅ | flutter_secure_storage pour tokens |
| M3 Communication non sécurisée | ✅ | HTTPS forcé via AppConfig.apiUrl |
| M4 Mauvaise gestion d'identifiants | ✅ | Tokens hors code, scopés par device |
| M5 Cryptographie faible | ✅ | Pas de crypto maison ; FCM/SignalR géré |
| M6 Code privilégié non protégé | ✅ | Configuration via --dart-define |
| M7 Mauvaise qualité du code client | Lints + tests à étoffer (couverture en cours) | |
| M8 Falsification de code | Signature stores OK, root/jailbreak detection N/A | |
| M9 Reverse engineering | Obfuscation Dart à activer en release | |
| M10 Fonctionnalité superflue | ✅ | Pas d'API debug exposée en release |
Risque : un token volé ouvre l'accès au compte ; une mauvaise vérification côté serveur autorise des accès non prévus.
Mesures :
SessionServiceest l'unique propriétaire des tokens pour Dio, les repositories et SignalR.- Le
ApiClient(lib/core/api_client.dart) attache automatiquement leAuthorization: Bearer <access_token>à chaque requête privée. - Plusieurs
401simultanés partagent un seul refresh. Chaque requête est rejouée au maximum une fois et un403ne lance aucun refresh. - Un refus
401du refresh purge la session ; une panne réseau, un429ou un5xxla conserve. Une réponse tardive après logout ou changement de compte ne peut pas réinstaller les anciens tokens. - L'autorisation fine reste de la responsabilité de l'API (cf.
TableMasterApi/SECURITY.md). L'app n'expose jamais d'écran "admin" basé uniquement sur un drapeau local.
Risque : tokens ou données sensibles accessibles à un attaquant en cas de root/jailbreak ou backup.
Mesures :
- Tous les jetons (
access_token,refresh_token,user_id,fcm_token) stockés viaflutter_secure_storage— Keychain iOS / EncryptedSharedPreferences Android. - Aucune persistance des mots de passe ni des PII utilisateur.
- Au
logout, la classeAuthRepositoryImplpurge explicitement toutes les clés sensibles avant de fermer la session.
Risque : MITM sur Wi-Fi public, sniffing.
Mesures :
- L'URL de l'API est définie via
--dart-define-from-file=config/{env}.jsonet toujours en HTTPS pourprod.json. - L'app n'autorise pas les certificats invalides (paramètres Dio par défaut).
- Le démarrage refuse une URL API de production qui n'utilise pas HTTPS. Le hub SignalR (
signalr_netcore) utilise alors WSS. - Le token SignalR transmis dans la query string imposée par le navigateur est filtré des événements et breadcrumbs Sentry.
- Les écrans privés rejoignent
user_{id}ourestaurant_{id}après validation serveur de leur droit. - L'écran client de réservation rejoint
availability_{restaurantId}. Il ne reçoit que l'identifiant du restaurant, puis recharge les disponibilités par HTTP. - Après reconnexion et au retour au premier plan, les groupes actifs sont rejoints avant l'émission du signal de resynchronisation.
- Les rafales sont regroupées et les réponses HTTP devenues obsolètes après un changement de filtre ou de date sont ignorées.
- Une disponibilité en erreur reste explicitement inconnue ; la validation de la réservation est désactivée jusqu'à un chargement réussi.
Les notifications issues de l'outbox API portent un eventId. L'application conserve pendant sept jours un reçu dans flutter_secure_storage. Deux livraisons concurrentes ou une reprise après redémarrage n'affichent qu'une notification logique ; l'identifiant de notification système est déterministe.
Mesures :
- Aucun secret API n'est embarqué dans l'app (clés Firebase publiques par nature).
- Les configs
config/*.jsonne contiennent que des URLs et des feature flags publics. - Le DSN Sentry est injecté au build/run via
--dart-define=SENTRY_DSN=...ou le secret CISENTRY_DSN_FLUTTER, jamais écrit en dur.
Mesures :
- L'app ne fait pas de cryptographie maison.
- La crypto est déléguée à : OS pour le secure storage, OS pour TLS, Firebase pour FCM, .NET pour JWT (vérifié côté serveur, jamais côté client).
Mesures :
- Configuration injectée au build via
--dart-define-from-file— aucune valeur sensible dans le code. - Pas de "debug menu" dans le binaire
release. - Sentry Flutter est activé seulement si
SENTRY_DSNest fourni ;SENTRY_ENABLE_STARTUP_TEST_EVENTsert uniquement au test local debug.
Mesures :
- Lints
flutter_lints ^5.0.0actifs (analysis_options.yaml). - Tests unitaires sur les repositories des 4 features critiques (auth, reservation, restaurant, user) — voir
test/. flutter analyzelancé en CI (.github/workflows/flutter.yml).
À renforcer : étendre la couverture aux 7 features restantes (cf. test/README.md).
Mesures :
- Build release Android signé par keystore privée (hors Git).
- Build iOS via Apple Developer Account (provisioning géré côté Xcode/Codemagic).
Hors scope actuel : root/jailbreak detection (justifié — app non bancaire, données restaurant à faible criticité).
État actuel : pas d'obfuscation Dart activée.
À activer pour release prod :
flutter build apk --release --obfuscate --split-debug-info=build/symbols/
flutter build ipa --release --obfuscate --split-debug-info=build/symbols/Mesures :
- Aucun écran de debug exposé en mode release (vérifié via
kReleaseMode). - Logs
AppLoggerfiltrés en release (niveauinfominimum). - Sentry collecte les erreurs applicatives et traces avec
sendDefaultPii=false. - Pas d'endpoint réseau additionnel atteint par l'app au-delà de l'API officielle et de Sentry.
- Consentement : à la première utilisation, l'utilisateur accepte les CGU et la politique de confidentialité.
- Droit à l'effacement : implémenté côté API (
UserRepositoryImpl.deleteAccount) et exposé dans l'écran Compte. - Données collectées : email, prénom, nom, téléphone (restaurateur), géoloc utilisée localement (jamais persistée).
- Notifications : token FCM stocké côté serveur, lié au user, supprimé au logout.
| Quand | Action |
|---|---|
| À chaque PR | flutter analyze + flutter test (CI) |
| À chaque release | flutter build avec --obfuscate + vérifier la taille binaire |
| Trimestriel | flutter pub outdated + revue des plugins natifs |
| Annuel | Revue manuelle de ce document |