PD-98 — Retour d'expérience¶
📚 Navigation User Story
| Document | | | ---------- | -- | | 📋 [Spécification](PD-98-specification.md) | | | 🛠️ [Plan d'implémentation](PD-98-plan.md) | | | ✅ [Critères d'acceptation](PD-98-acceptability.md) | | | 📝 **Retour d'expérience** | *(ce document)* | [← Retour à mobile-ios](../PD-195-epic.md) · [↑ Index User Story](index.md)1. Résumé exécutif¶
La User Story PD-98 visait à implémenter le stockage sécurisé de K_master dans le iOS Keychain avec les attributs de sécurité maximaux (WHEN_UNLOCKED_THIS_DEVICE_ONLY, non exportable, non sync iCloud). L'implémentation est fonctionnelle et fournit une API CRUD complète avec logs sécurisés, mais présente 1 écart MINEUR (zeroization non systématique des buffers intermédiaires). Verdict : ACCEPTÉ AVEC RÉSERVES.
2. Points fluides¶
- expo-secure-store : bibliothèque Expo bien documentée, API simple et fiable
- Attributs Keychain :
WHEN_UNLOCKED_THIS_DEVICE_ONLYcorrectement configuré - Helpers base64 natifs : implémentation manuelle sans dépendance à btoa/atob (non disponibles en RN)
- API CRUD complète :
storeMasterKey,getMasterKey,deleteMasterKey,existsMasterKey - Typage TypeScript strict :
KeychainResult<T>avec union typeKeychainError - Logs sécurisés : aucune valeur sensible dans les logs, uniquement événements génériques
- Tests exhaustifs : 500+ lignes de tests couvrant tous les scénarios (succès, erreurs, sécurité)
- Versioning clé : préfixe
com.probatiovault.kmaster.v1pour migration future - Gestion erreurs : mapping intelligent des erreurs SecureStore vers codes applicatifs
- clearMasterKeyBuffer : fonction publique pour effacement explicite après usage
3. Points difficiles¶
| Difficulté | Contexte |
|---|---|
| btoa/atob absents | React Native ne fournit pas ces fonctions standard, nécessitant une implémentation base64 manuelle |
| Plateforme web | expo-secure-store ne supporte pas le web, fallback explicitement refusé par la spec |
| Mocking SecureStore | Les tests nécessitent un mock complet de l'API avec simulation de storage interne |
| Détection device locked | Les messages d'erreur iOS varient selon les versions, mapping heuristique nécessaire |
4. Hypothèses révélées tardivement¶
| Hypothèse initiale | Réalité découverte |
|---|---|
| btoa/atob disponibles en React Native | FAUX — Nécessite implémentation manuelle avec alphabet BASE64_CHARS |
| SecureStore supporte toutes les plateformes | FAUX — iOS et Android uniquement, web explicitement non supporté |
| Messages d'erreur iOS standardisés | FAUX — Variation selon versions iOS, mapping heuristique par mots-clés |
| Face ID/Touch ID intégrable simplement | FAUX — Nécessite requireAuthentication: true mais laissé en TODO pour future US |
5. Invariants complexes à implémenter¶
| Invariant | Complexité |
|---|---|
| Taille exacte 32 bytes | Validation stricte à l'écriture ET à la lecture (détection corruption) |
| WHEN_UNLOCKED_THIS_DEVICE_ONLY | Configuration expo-secure-store, non contournable |
| Pas de log sensible | Revue manuelle de tous les console.log/error/warn, uniquement messages génériques |
| Idempotence delete | deleteMasterKey() retourne success même si clé inexistante |
| Non-exportabilité | Garantie par l'attribut iOS Keychain, pas de code applicatif nécessaire |
6. Dette technique¶
| Dette | Impact | Priorité |
|---|---|---|
| Zeroization non systématique | Strings base64 en mémoire après encodage/décodage | MOYENNE |
| clearBuffer simple | Un seul fill(0), pas de double passe ni volatile write | BASSE |
| Face ID/Touch ID désactivé | requireAuthentication commenté, TODO pour future US | BASSE |
| existsMasterKey lit la clé | Lecture complète au lieu de simple check existence | BASSE |
7. Risques résiduels¶
| Risque | Probabilité | Impact | Mitigation suggérée |
|---|---|---|---|
| String base64 en mémoire | Élevée | FAIBLE | Limitation JavaScript acceptée, documenter |
| Mapping erreurs incomplet | Moyenne | FAIBLE | Ajouter nouveaux patterns si erreurs non reconnues |
| Pas de Face ID obligatoire | Faible | MOYEN | Implémenter dans future US sécurité renforcée |
| Corruption données stockées | Très faible | MOYEN | Détection taille à la lecture, logging explicite |
8. Améliorations processus¶
| Amélioration | Bénéfice attendu |
|---|---|
| Documenter absence btoa/atob | Éviter surprise aux futurs développeurs React Native |
| Activer requireAuthentication | Protection Face ID/Touch ID pour accès K_master |
| Ajouter zeroize sur encoded | Effacer string base64 après usage (best-effort via = '') |
| Test acceptance iOS réel | Valider comportement sur device physique (simulator != real) |
| Monitoring erreurs UNKNOWN | Logger pattern non reconnu pour améliorer mapError |
9. Enseignements clés¶
-
expo-secure-store est fiable — L'abstraction Expo au-dessus du Keychain iOS fonctionne bien et simplifie considérablement l'implémentation par rapport à l'API native.
-
React Native n'est pas un navigateur — Les APIs standard comme btoa/atob ne sont pas disponibles. Toujours vérifier la disponibilité des primitives avant de les utiliser.
-
Les logs sont un vecteur de fuite — La revue systématique des console.log est essentielle pour éviter d'exposer des données sensibles. Les messages doivent être génériques ("K_master stored successfully" pas "Stored key: xxx").
-
L'effacement mémoire en JavaScript est best-effort — Les strings sont immutables et le GC non déterministe. Documenter cette limitation plutôt que prétendre une sécurité parfaite.
-
Le versioning dès le départ évite la dette — Le préfixe
v1danscom.probatiovault.kmaster.v1permet une migration future sans casser la compatibilité.