Files
billisdead 92e67d0769 feat: application n8n Pilot complète (Expo managed workflow)
- Stack : Expo Router, Axios, Zustand, React Native Paper (thème sombre), date-fns
- Sécurité : secrets dans Android Keystore via expo-secure-store, TLS obligatoire,
  headers X-N8N-API-KEY + X-App-Token injectés par intercepteur Axios
- API : client.ts centralisé + workflows.ts + executions.ts (TypeScript strict)
- Store : Zustand appStore avec chargement depuis secure store au démarrage
- Hooks : usePolling (générique), useWorkflows, useExecutions
- Composants : StatusBadge, WorkflowCard, ExecutionCard, SkeletonLoader
- Screens : Dashboard, Workflows, Executions, Logs (détail exécution), Settings
- Navigation Expo Router : 4 tabs + stack Logs + écran Setup initial
- Docs : INSTALL.md, UPDATE.md, BACKUP.md, HAPROXY.md, SECURITY.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 17:31:55 +02:00

5.7 KiB

Sécurité — n8n Pilot

Modèle de menaces

Acteurs et vecteurs

Menace Impact Probabilité Mitigation
Vol de l'appareil Android Accès aux credentials n8n Moyen Android Keystore chiffré, biométrie optionnelle
Interception réseau (MITM) Exposition de la clé API Faible (TLS) TLS obligatoire, refus HTTP
Fuite du token HAProxy Accès non autorisé à n8n Moyen Rotation régulière, token hors bundle
Compromission du build APK Backdoor dans l'app Faible Keystore signé, builds EAS reproductibles
Brute force API Épuisement quotas n8n Faible Rate limiting HAProxy (429)
Logs applicatifs exposés Fuite de secrets Faible Jamais de log de secrets, même en dev

Principes appliqués

Least Privilege (moindre privilège)

La clé API n8n doit être créée avec le scope minimal nécessaire :

Recommandé :
✓ workflows:list      — lister les workflows
✓ workflows:read      — lire les détails
✓ workflows:update    — activer/désactiver (toggle)
✓ executions:list     — voir l'historique
✓ executions:read     — lire les logs
✓ executions:delete   — supprimer des exécutions
✓ workflows:run       — déclencher manuellement

Non recommandé :
✗ credentials:*       — inutile pour cette app
✗ users:*             — inutile pour cette app
✗ admin:*             — jamais

Comment créer la clé dans n8n :

  1. Settings > n8n API
  2. Create API Key
  3. Nommer la clé "n8n-pilot-mobile"
  4. Définir les scopes minimaux ci-dessus
  5. Copier la clé — elle n'est affichée qu'une seule fois

Defense in Depth (défense en profondeur)

L'accès à l'API n8n passe par deux barrières indépendantes :

Requête → [TLS] → [X-App-Token HAProxy] → [X-N8N-API-KEY n8n] → Données

Si un token est compromis :

  • Compromission du X-App-Token seul → HAProxy bloque, n8n jamais atteint
  • Compromission de la clé API seul → sans le X-App-Token, HAProxy bloque à 403
  • Les deux compromis → rotation immédiate des deux (procédures dans HAPROXY.md et BACKUP.md)

Zero Trust (réseau local inclus)

n8n ne doit pas être accessible directement sur le réseau, même en local. Toutes les requêtes passent par HAProxy qui valide le token.

# Bloquer l'accès direct au port n8n (iptables)
iptables -A INPUT -p tcp --dport 5678 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 5678 -j DROP

Gestion des secrets — cycle de vie

Stockage

┌─────────────────────────────────────────────────────┐
│ Appareil Android                                     │
│  ┌─────────────────────────────────────────────┐    │
│  │ Android Keystore (expo-secure-store)         │    │
│  │   n8n_base_url   → https://n8n.example.com  │    │
│  │   n8n_api_key    → clé API (chiffrée)       │    │
│  │   n8n_app_token  → token HAProxy (chiffré)  │    │
│  └─────────────────────────────────────────────┘    │
│                                                      │
│  État React (Zustand) — en mémoire uniquement :      │
│   config.baseUrl   → copie non sensible              │
│   config.isConfigured → booléen                      │
│   JAMAIS : apiKey, appToken en mémoire JS            │
└─────────────────────────────────────────────────────┘

Transit

  • Les secrets sont lus depuis le Keystore à chaque requête HTTP dans client.ts
  • Ils sont injectés dans les headers HTTP et ne sont pas loggués
  • Ils ne sont jamais :
    • Sérialisés dans AsyncStorage
    • Inclus dans des logs (même en dev)
    • Embarqués dans le bundle JS (app.json, package.json, code source)
    • Envoyés à des services tiers (analytics, crash reporters)

Rotation

Secret Fréquence recommandée Procédure
Clé API n8n Tous les 180 jours, ou en cas de compromission Créer nouvelle clé dans n8n, mettre à jour dans l'app
X-App-Token Tous les 90 jours Voir docs/HAPROXY.md
Keystore EAS Jamais (sauf compromission) Voir docs/BACKUP.md

Checklist avant mise en production

Application

  • app.json : userInterfaceStyle = "dark" (pas d'info sensible en clair)
  • .env non commité dans git (git status ne montre pas .env)
  • Aucun console.log de valeurs sensibles dans le code
  • __DEV__ gate sur tous les logs dans errorHandler.ts
  • Expo SDK à jour — vérifier les CVE : npx expo-doctor
  • Dépendances à jour : npm audit

Infrastructure

  • HAProxy : TLS 1.2 minimum, TLS 1.0/1.1 désactivés
  • Certificat TLS valide et non expiré
  • n8n inaccessible directement sur le port 5678 depuis l'extérieur
  • Rate limiting HAProxy activé (429 configuré)
  • Logs HAProxy ne contiennent pas les valeurs des headers secrets

n8n

  • Clé API avec scope minimal (voir § Least Privilege ci-dessus)
  • n8n mis à jour vers la dernière version stable
  • Sauvegardes n8n actives (workflows, credentials n8n)

Appareil

  • Verrouillage d'écran activé (PIN, pattern ou biométrie)
  • Biométrie configurée dans l'app si disponible
  • Appareil Android 8+ (API 26+) pour garantir la robustesse du Keystore