# Phase F — Sécurité Frontend --- ## F1. Secrets et données sensibles ### Variables VITE_* exposées au bundle | Variable | Contenu | Sensible ? | |----------|---------|-----------| | `VITE_API_URL` | URL API backend | ❌ Public | | `VITE_WS_URL` | URL WebSocket | ❌ Public | | `VITE_STREAM_URL` | URL streaming | ❌ Public | | `VITE_UPLOAD_URL` | URL upload | ❌ Public | | `VITE_APP_NAME` | Nom de l'app | ❌ Public | | `VITE_DEBUG` | Flag debug | ❌ Non sensible | | `VITE_USE_MSW` | Flag MSW | ❌ Dev only | | `VITE_FCM_VAPID_KEY` | Clé push notifications | ⚠️ Public par design (VAPID) | | `VITE_FEATURE_*` | Feature flags | ❌ Non sensible | **Verdict** : Aucune clé API secrète exposée côté client. ✅ ### Fichiers .env - `.env.local` (450B) : Contient `VITE_DOMAIN`, `VITE_API_URL`, `VITE_WS_URL`, `VITE_STREAM_URL` — **pas de secrets** ✅ - `.env.production` (1.8KB) : Contient URLs et config — **pas de secrets** ✅ - `.env.example` (2.2KB) : Template **Attention** : `.env.local` et `.env.production` sont versionnés (présents dans le repo). Le `.gitignore` ne semble pas exclure `.env.local`. Même si le contenu n'est pas sensible actuellement, c'est un **risque si quelqu'un ajoute un secret à l'avenir**. ### Stockage JWT - **httpOnly cookies** : Les tokens JWT sont gérés côté backend via cookies httpOnly ✅ - `TokenStorage.getAccessToken()` retourne `null` en mode cookie — pas d'accès JS aux tokens ✅ - `tokenStorage.ts` est un wrapper de compatibilité, pas de stockage réel en localStorage ✅ --- ## F2. XSS ### `dangerouslySetInnerHTML` | Fichier | Ligne | Source des données | Sanitization | |---------|-------|--------------------|-------------| | `features/chat/components/ChatMessages.tsx` | 145-147 | `message.content` (backend) | ✅ `sanitizeChatMessage()` via DOMPurify | | `features/chat/components/virtualized-chat-messages/VirtualizedChatMessageItem.tsx` | 58-60 | `message.content` (backend) | ✅ `sanitizeChatMessage()` via DOMPurify | **Sanitization** : `utils/sanitize.ts` (429L) utilise DOMPurify avec : - Allowlist stricte de tags HTML [sanitize.ts] - Allowlist d'attributs [sanitize.ts] - URL schemes limitées (http, https, mailto) [sanitize.ts] - `javascript:` protocol filtré ✅ **Verdict XSS** : ✅ Les deux usages de `dangerouslySetInnerHTML` sont correctement sanitizés. ### Autres vecteurs XSS - `eval()` / `new Function()` : **0 occurrence** ✅ - Template literals dans le DOM : Non détecté ✅ - `document.write` : **0 occurrence** ✅ --- ## F3. Stockage client ### Données en localStorage | Clé | Données | Sensible ? | Expiration | |-----|---------|-----------|-----------| | `ui-storage` | theme, language, sidebarOpen | ❌ | Persist | | `veza-cart-storage` | Items du panier | ❌ | Persist | | `auth-storage` | `isAuthenticated` (boolean) | ❌ | Persist | | `rememberedEmail` | Email utilisateur | ⚠️ PII | Persist | | `veza_offline_queue` | Requêtes en attente | ⚠️ Peut contenir des données | Nettoyé | | `PENDING_ANALYTICS_STORAGE_KEY` | Analytics payload | ❌ | Nettoyé | | `feature-highlight-*` | Dismissal flags | ❌ | Persist | | `pwa-install-dismissed` | Flag | ❌ | Persist | | `veza_wrong_server_shown` | Flag toast | ❌ | Persist | | **Developer API keys** | **Clés API** | **🔴 OUI** | **Persist** | **Problème critique** : `services/developerService.ts` stocke des clés API dans localStorage. Même si ce sont des clés de développeur (probablement des API keys publiques), le stockage en localStorage les expose à toute extension de navigateur ou code tiers injecté. **Recommandation : déléguer la gestion au backend.** ### sessionStorage - Pas d'usage sensible détecté ✅ --- ## F4. Dépendances ### Vulnérabilités connues [DONNÉES INSUFFISANTES — nécessite `npm audit` sur la machine] ### Dépendances à risque | Dépendance | Version | Risque | Usage | |-----------|---------|--------|-------| | `dompurify` | 3.3.x | ✅ Activement maintenu | Sanitization | | `axios` | 1.13.x | ✅ Récent | HTTP | | `swagger-ui-react` | 5.31.x | ⚠️ Exposé en production ? | Dev tools | | `hls.js` | 1.6.x | ✅ Maintenu | Streaming | **Attention** : `swagger-ui-react` et `swagger-ui-dist` sont en `dependencies` (pas `devDependencies`). Si le composant SwaggerUI est accessible en production, cela expose la documentation API. **Vérifier que la route `/developer` est bien protégée et gated.** --- ## F5. Autres vecteurs ### Open redirect | Fichier | Risque | Détail | |---------|--------|--------| | `features/playlists/hooks/usePlaylistNotifications.ts:203,219,235,251` | 🔴 **HAUT** | `window.location.href = notification.link!` — URL provenant du backend, pas de validation. Si un attaquant compromet les notifications, il peut rediriger vers un site malveillant. | | Autres `window.location.href` | ✅ Sûr | Tous vers des chemins statiques (`/login`, `/marketplace`, etc.) | ### CORS / CSP - **CORS** : Géré côté backend. Le proxy Vite en dev élimine les problèmes CORS [vite.config.ts:63-76] ✅ - **CSP** : [DONNÉES INSUFFISANTES — nécessite inspection des headers serveur] ### Prototype pollution - Pas d'usage de `lodash.merge` ou similaire détecté ✅ - `immer` (10.x) utilisé pour l'immutabilité — protège contre la mutation directe ✅ --- ## Classement des vulnérabilités | Gravité | Vulnérabilité | Fichier:ligne | Exploitabilité | Correction urgence | |---------|--------------|---------------|----------------|-------------------| | 🔴 CRITIQUE | Open redirect via notification.link | `usePlaylistNotifications.ts:203,219,235,251` | Moyenne (nécessite compromission backend/notifications) | Immédiate — valider l'URL (same-origin ou allowlist) | | 🟠 HAUTE | Clés API en localStorage | `developerService.ts:33` | Faible (nécessite accès au navigateur) | Court terme — migrer vers backend | | 🟡 MOYENNE | `.env.local` versionné | `.env.local` | Faible (pas de secrets actuels) | Ajouter `.env.local` au `.gitignore` | | 🟡 MOYENNE | swagger-ui en production | `package.json` (dependencies) | Faible (route protégée) | Déplacer en devDependencies si non nécessaire en prod | | 🟢 BASSE | `rememberedEmail` en localStorage | `LoginPage.tsx:115` | Très faible (PII minimal) | Acceptable avec notice RGPD | --- ## Score Sécurité implicite Ce score n'est pas dans le tableau principal car la pondération est ×1.5, mais les observations sont globalement positives : - ✅ httpOnly cookies pour JWT - ✅ CSRF protection - ✅ DOMPurify pour `dangerouslySetInnerHTML` - ✅ Zod validation sur les réponses API - ✅ Pas de `eval()` ni secrets exposés - ❌ Open redirect dans usePlaylistNotifications - ❌ Clés API en localStorage **Score Sécurité : 7/10**