Files
stupid-simple-network-inven…/SECURITY_FIXES_APPLIED.md
T
olivier 88cf6458d0 Initial commit — Stupid Simple Network Inventory
Application web d'inventaire réseau manuel avec FastAPI, Vue 3 et Docker.
Inclut l'authentification JWT, la découverte ICMP, et la topologie en cards CSS.

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

5.0 KiB

Security Fixes Applied

Date: 2026-05-06

P0-001 — SEC-FIX-001 : Changement de mot de passe obligatoire au premier login

Problème

Le compte admin par défaut utilisait admin/admin. N'importe qui ayant accès au port 8080 pouvait se connecter.

Changements

backend/models.py

  • Colonne must_change_password BOOLEAN NOT NULL DEFAULT 0 ajoutée sur User.

backend/main.py

  • Nouvelle migration idempotente _migrate_users_must_change_password()ALTER TABLE users ADD COLUMN must_change_password BOOLEAN NOT NULL DEFAULT 0 si absente.
  • _migrate_users() : support de la variable d'environnement INITIAL_ADMIN_PASSWORD.
    • Si définie → mot de passe fourni, must_change_password = 0.
    • Sinon → mot de passe admin, must_change_password = 1 (changement forcé au premier login).
  • Routeurs vlans, devices, links, discovery protégés par require_password_changed au lieu de get_current_user.

backend/routers/auth.py

  • Dépendance require_password_changed : retourne 403 "Password change required" si must_change_password = 1.
  • TokenOut enrichi du champ must_change_password: bool.
  • login() retourne must_change_password.
  • update_account() passe must_change_password à False après changement de mot de passe réussi.
  • GET /me retourne must_change_password.

frontend/src/auth.js

  • Ref _mustChange persistée dans localStorage('auth_mustchange').
  • mustChangePassword computed exporté.
  • setAuth(token, username, mustChange) / clearAuth() mis à jour.

frontend/src/App.vue

  • Branche v-else-if="mustChangePassword" : affiche <AccountModal :forced="true"> avant l'application.
  • onLogin et onAccountUpdated propagent le flag ; loadAll n'est appelé que si mustChangePassword est faux.
  • onMounted conditionnel sur !mustChangePassword.value.

frontend/src/components/AccountModal.vue

  • Prop forced (Boolean, défaut false) :
    • Masque le bouton ✕ et le bouton Annuler.
    • Empêche la fermeture par clic sur l'overlay.
    • Affiche une bannière d'avertissement.
    • Rend le champ "Nouveau mot de passe" obligatoire.

frontend/src/i18n.js

  • Clés ajoutées (fr/en/es) : mustChangePasswordWarning, newPasswordRequired.

Utilisation

# docker-compose.yml — optionnel
environment:
  - INITIAL_ADMIN_PASSWORD=MonMotDePasseSecurisé

Sans cette variable, le premier login avec admin/admin force immédiatement le changement de mot de passe.


P1-001 — SEC-FIX-002 : Rate limiting sur POST /api/auth/login

Problème

Aucune limitation du nombre de tentatives de connexion — brute-force possible.

Changements

frontend/rate_limit.conf (nouveau)

  • limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;

frontend/Dockerfile

  • COPY rate_limit.conf /etc/nginx/conf.d/00_rate_limit.conf — chargé en premier (ordre alphabétique).

frontend/nginx.conf

  • Location spécifique = /api/auth/login avec limit_req zone=login burst=5 nodelay et limit_req_status 429.

backend/routers/auth.py

  • Rate limiting in-memory (sans dépendance externe) :
    • Par IP : 20 tentatives / 60 s
    • Par username : 10 tentatives / 900 s (15 min)
    • Compteurs réinitialisés après login réussi.
  • login() extrait l'IP via Request.client.host.
  • Retourne HTTP 429 "Too many attempts, try again later".

frontend/src/components/LoginPage.vue

  • Gère le status 429 → affiche t('tooManyAttempts').

frontend/src/i18n.js

  • Clé ajoutée : tooManyAttempts.

P1-002 — SEC-FIX-003 : Validation serveur des entrées sur PUT /api/auth/account

Problème

Aucune validation sur new_username et new_password — mots de passe vides ou noms d'utilisateurs invalides acceptés.

Changements

backend/routers/auth.py

  • _validate_new_password(password) : min 8 caractères, au moins une lettre et un chiffre. Lève 400 avec code password_too_short ou password_too_weak.
  • _validate_new_username(username) : [a-zA-Z0-9._-]{1,64}. Lève 400 avec code username_invalid.
  • update_account() appelle ces fonctions avant modification.

frontend/src/components/AccountModal.vue

  • Validation client miroir (évite un aller-retour réseau pour les cas évidents).
  • Mapping des codes d'erreur backend → clés i18n : password_too_short, password_too_weak, username_invalid.

frontend/src/i18n.js

  • Clés ajoutées (fr/en/es) : passwordTooShort, passwordTooWeak, usernameInvalid.

Fichiers modifiés

Fichier Fixes
backend/models.py P0-001
backend/main.py P0-001
backend/routers/auth.py P0-001, P1-001, P1-002
frontend/rate_limit.conf P1-001 (nouveau)
frontend/Dockerfile P1-001
frontend/nginx.conf P1-001
frontend/src/auth.js P0-001
frontend/src/i18n.js P0-001, P1-001, P1-002
frontend/src/App.vue P0-001
frontend/src/components/LoginPage.vue P0-001, P1-001
frontend/src/components/AccountModal.vue P0-001, P1-002