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>
15 KiB
Revue securite apres corrections
Date: 2026-05-06
Base de comparaison: SECURITY_AUDIT_BASE.md, SECURITY_FIX_PLAN_FOR_CLAUDE.md, SECURITY_FIXES_APPLIED.md et code actuel.
Mode: revue statique locale, sans exploitation. Aucun fichier applicatif n'a ete modifie.
Synthese
Les corrections declarees dans SECURITY_FIXES_APPLIED.md sont presentes dans le code pour les trois premiers sujets: changement force au premier login, rate limiting du login, validation minimale du changement de compte. Elles reduisent le risque principal de bootstrap et de bruteforce.
La correction SEC-FIX-001 reste partielle pour les installations deja creees avant la migration: l'ajout de colonne met must_change_password a 0 par defaut. Dans la base locale observee, l'utilisateur admin a must_change_password=0. Si ce compte utilise encore l'ancien mot de passe public, il ne sera pas force a changer. La documentation est egalement en retard sur le code: plusieurs fichiers decrivent encore get_current_user comme dependance des routeurs metier et ne documentent pas le nouveau flux must_change_password.
Verification effectuee:
- Parsing Python par AST: OK, 9 fichiers parses.
- Build frontend Vite vers
/tmp/topologie-vite-build: OK. - Aucun test automatise dedie n'a ete trouve dans
backendoufrontend.
SEC-FIX-001 - Changement de mot de passe obligatoire au premier login
Statut: partiellement corrige
Preuve dans le code:
backend/models.py:6-12ajouteUser.must_change_password.backend/main.py:78-110creeadminavecmust_change_password=1siINITIAL_ADMIN_PASSWORDest absent, et0si la variable est fournie.backend/main.py:130-133protege les routeurs metier avecDepends(require_password_changed).backend/routers/auth.py:97-100refuse les routeurs proteges avec 403 si le changement est requis.backend/routers/auth.py:149-172remetmust_change_passwordaFalseapres changement de mot de passe.frontend/src/App.vue:3-11afficheAccountModalforcee avant l'application simustChangePasswordest vrai.frontend/src/components/AccountModal.vue:93-97exige un nouveau mot de passe cote client en mode force.
Risque restant:
backend/main.py:63-75ajoute la colonne aux bases existantes avecDEFAULT 0; les comptes deja presents ne sont donc pas forces a changer.- La base locale contient
admin|0pourmust_change_password. docker-compose.ymlne montre pasINITIAL_ADMIN_PASSWORD;.env.exampleest absent.AGENTS.md,CLAUDE.mdetdocs/backend.mddecrivent encore l'ancien modeleDepends(get_current_user)ou l'ancien contrat de login.
Recommandation finale:
- Ajouter une migration de rattrapage explicite pour les anciennes bases, ou documenter une commande de remediation obligatoire.
- Documenter
INITIAL_ADMIN_PASSWORD,must_change_passwordetrequire_password_changeddansAGENTS.md,CLAUDE.md,docs/*et.env.example. - Ajouter un test couvrant base vide, base existante et acces CRUD avant/apres changement.
SEC-FIX-002 - Rate limiting sur POST /api/auth/login
Statut: corrige
Preuve dans le code:
frontend/rate_limit.conf:1definitlimit_req_zone.frontend/Dockerfile:10-11copienginx.confetrate_limit.conf.frontend/nginx.conf:6-13appliquelimit_req zone=login burst=5 nodelayet retourne 429 sur/api/auth/login.backend/routers/auth.py:43-76implemente un rate limit in-memory par username et par IP.backend/routers/auth.py:132-146applique ces controles avant verification du mot de passe.frontend/src/components/LoginPage.vue:69-74affiche un message dedie sur 429.
Risque restant:
- Le rate limit backend est en memoire: il est perdu au redemarrage et se fragmente avec plusieurs workers/process.
Request.client.hostvoit souvent l'adresse du proxy Nginx, pas le client final; le controle IP backend peut donc devenir global derriere proxy. Le controle Nginx compense dans le deploiement Compose fourni.- Les compteurs IP backend ne sont pas remis a zero apres login reussi.
- Aucun test automatise de fenetre, expiration ou non-enumeration n'a ete trouve.
Recommandation finale:
- Conserver le controle Nginx et soit documenter que le backend ne doit pas etre expose directement, soit gerer proprement
X-Forwarded-Fordepuis un proxy de confiance. - Ajouter des tests API pour echecs successifs, expiration de fenetre et succes apres expiration.
SEC-FIX-003 - Validation serveur des entrees sur PUT /api/auth/account
Statut: partiellement corrige
Preuve dans le code:
backend/routers/auth.py:103-117valide username et mot de passe.backend/routers/auth.py:157-165applique ces validations avant modification.frontend/src/components/AccountModal.vue:91-117applique une validation miroir.frontend/src/i18n.js:160-165,310-315,460-465contient les messages localises.
Risque restant:
- La politique mot de passe reste minimale:
password1ouadmin123respectent la regle lettre+chiffre et longueur 8. AccountUpdateaccepte les champs optionnels sans contraintes Pydantic; la robustesse depend des validations manuelles.- Les erreurs
Username already takenetCurrent password is incorrectne sont pas sous forme de codes stables et restent moins homogenes que les nouveaux codes. - Aucun test API dedie n'a ete trouve.
Recommandation finale:
- Renforcer la politique avec une liste de mots de passe evidents/refuses et des contraintes Pydantic (
Field,StringConstraints) en plus des helpers. - Normaliser/trim le username avant comparaison et stockage.
- Ajouter des tests pour mot de passe faible evident, username invalide, doublon et cas valide.
SEC-FIX-004 - JWT localStorage, expiration et invalidation
Statut: non corrige
Preuve dans le code:
frontend/src/auth.js:3-17stocke toujours le JWT danslocalStorage.frontend/src/api.js:6-9continue d'envoyer un bearer token lu par JavaScript.backend/routers/auth.py:38-80conserve une expiration de 7 jours et un payload{sub, exp}sans version de session.backend/routers/auth.py:162-168change le mot de passe sans invalider les tokens deja emis.
Risque restant:
- Vol/rejeu de JWT en cas de XSS, extension compromise ou poste compromis.
- Ancien token toujours valide apres changement de mot de passe jusqu'a expiration.
Recommandation finale:
- Migrer vers cookie
HttpOnly,Secure,SameSiteou, a minima, ajoutersession_version/token_versionen base et reduire l'expiration.
SEC-FIX-005 - CORS configurable ou supprime
Statut: non corrige
Preuve dans le code:
backend/main.py:122-127conserveallow_origins=["*"],allow_methods=["*"],allow_headers=["*"]..env.exampleest absent.
Risque restant:
- Configuration permissive si le backend est publie directement ou si l'auth migre vers cookies.
Recommandation finale:
- Supprimer CORS en mode meme origine ou ajouter
ALLOWED_ORIGINSexplicite. - Documenter que le backend doit rester interne.
SEC-FIX-006 - Encadrement discovery scan/ping
Statut: non corrige
Preuve dans le code:
backend/routers/discovery.py:72-86accepteips: list[str]sans validation IP ni limite de taille.backend/routers/discovery.py:89-129valide seulement le format CIDR et limite chaque reseau a 1024 hotes, mais pas le total de targets ni le perimetre autorise.backend/routers/discovery.py:52-60accepte un serveur DNS fourni librement.
Risque restant:
- Reconnaissance reseau authentifiee, surcharge CPU/process et DNS arbitraire.
Recommandation finale:
- Valider IP/CIDR/DNS, plafonner le total par requete, autoriser seulement les CIDR d'inventaire ou une allowlist, et ajouter rate limit.
SEC-FIX-007 - Validation stricte des modeles metier
Statut: non corrige
Preuve dans le code:
backend/routers/devices.py:11-33,backend/routers/vlans.py:11-15,backend/routers/links.py:11-15utilisent encore desstrlibres sans bornes, enums ni validation URL/IP/CIDR/couleur.- Les liens externes ont
rel="noopener"mais pasnoreferrer:frontend/src/components/DeviceManager.vue:137,frontend/src/components/TopologyGraph.vue:35,56,104,142.
Risque restant:
- Donnees incoherentes, champs enormes, URL dangereuses et surface XSS future.
Recommandation finale:
- Ajouter contraintes Pydantic v2, enums serveur, validation URL
http/https, IP/CIDR et couleur hex. - Remplacer
rel="noopener"parrel="noreferrer noopener".
SEC-FIX-008 - En-tetes de securite HTTP
Statut: non corrige
Preuve dans le code:
frontend/nginx.conf:1-25ne definit pas CSP,X-Content-Type-Options,Referrer-Policy,Permissions-Policy,X-Frame-Optionsouframe-ancestors.- La seule configuration ajoutee concerne
limit_req:frontend/nginx.conf:6-8.
Risque restant:
- Durcissement navigateur absent dans la configuration fournie.
Recommandation finale:
- Ajouter les en-tetes dans Nginx ou fournir une configuration reverse-proxy de reference verifiee.
SEC-FIX-009 - Contrat TLS/reverse-proxy
Statut: non corrige
Preuve dans le code:
docker-compose.yml:14-15expose toujours"8080:80"sur toutes les interfaces.- Aucune
.env.exampleni documentation de bind local/reverse proxy TLS n'a ete ajoutee.
Risque restant:
- Exposition HTTP involontaire sur un LAN non fiable avec interception d'identifiants/tokens.
Recommandation finale:
- Documenter HTTPS obligatoire hors local et recommander
127.0.0.1:8080:80pour un proxy local. - Fournir un exemple reverse-proxy TLS.
SEC-FIX-010 - Gestion du secret JWT
Statut: non corrige
Preuve dans le code:
backend/routers/auth.py:20-33cree toujoursdata/secret_key.txtviaopen(..., "w")sans permissions explicites.docker-compose.yml:6-7monte toujours./db_data:/app/data..gitignoreet.env.examplesont absents.
Risque restant:
- Fuite locale de cle JWT et forge de tokens jusqu'a rotation.
Recommandation finale:
- Creer le fichier avec permissions
0600, ignorerdb_data/, documenter rotation et supporter un secret Docker/env obligatoire en production.
SEC-FIX-011 - Durcissement conteneurs
Statut: non corrige
Preuve dans le code:
backend/Dockerfile:1-8etfrontend/Dockerfile:8-12ne definissent pas d'utilisateur non-root.docker-compose.yml:1-20ne definit pascap_drop,security_opt,read_only, limites ressources ni healthchecks.
Risque restant:
- Impact augmente en cas de compromission d'un conteneur.
Recommandation finale:
- Passer en non-root, ajouter
cap_drop: [ALL], garderNET_RAWseulement pour le backend, ajouterno-new-privileges, healthchecks et volumes temporaires explicites.
SEC-FIX-012 - Logs securite structures
Statut: non corrige
Preuve dans le code:
- Aucun logging structure n'est present dans
backend/routers/auth.py,devices.py,vlans.py,links.pyoudiscovery.py.
Risque restant:
- Investigation limitee en cas d'incident: login, scans, suppressions et rate limits ne sont pas tracables.
Recommandation finale:
- Ajouter logs structures sans secrets pour authentification, changements de compte, CRUD, scans et rate limits.
SEC-FIX-013 - Foreign keys SQLite
Statut: non corrige
Preuve dans le code:
backend/database.py:7-10cree l'engine sans event SQLAlchemy pourPRAGMA foreign_keys=ON.- Les
ForeignKeyrestent declares dansbackend/models.py, mais SQLite ne les enforce pas sans pragma par connexion.
Risque restant:
- Incoherences relationnelles possibles via evolutions futures, migrations ou erreurs applicatives.
Recommandation finale:
- Activer
PRAGMA foreign_keys=ONvia event SQLAlchemy et tester suppressions/creation d'interfaces/liens invalides.
SEC-FIX-014 - Supply chain et builds reproductibles
Statut: non corrige
Preuve dans le code:
frontend/Dockerfile:3-4utilise toujoursnpm installau lieu denpm ci.frontend/package.jsoncontient encorecytoscape.- Aucune procedure d'audit dependances n'a ete ajoutee.
Risque restant:
- Builds moins reproductibles et dependances inutiles/vulnerables plus difficiles a suivre.
Recommandation finale:
- Utiliser
npm ci, supprimercytoscapes'il est inutilise, documenternpm auditet l'audit Python en conservant le pinbcrypt==3.2.2.
SEC-FIX-015 - Import JSON borne et valide
Statut: non corrige
Preuve dans le code:
frontend/src/App.vue:198-220lit le fichier complet, parse sans schema, importe en boucle et ignore silencieusement les erreurs par.catch(() => {}).
Risque restant:
- Import incoherent, erreurs masquees et deni de service local par fichier volumineux.
Recommandation finale:
- Ajouter limite de taille, validation de schema, compteur d'erreurs et retour utilisateur detaille.
SEC-FIX-016 - Suppression de v-html
Statut: non corrige
Preuve dans le code:
frontend/src/App.vue:30utilise encorev-html="tab.icon".
Risque restant:
- Risque XSS defense-in-depth si une future icone devient dynamique ou non controlee.
Recommandation finale:
- Remplacer par texte, composants d'icones ou SVG statique sans
v-html.
SEC-FIX-017 - Endpoint health public documente ou restreint
Statut: partiellement corrige
Preuve dans le code:
backend/main.py:136-138expose toujours/api/healthpubliquement avec seulement{"status": "ok"}, sans detail sensible.- La decision de securite n'est pas documentee dans les fichiers lus.
Risque restant:
- Exposition inutile d'information de disponibilite si le proxy publie trop largement l'API.
Recommandation finale:
- Documenter explicitement que l'endpoint est public et minimal, ou le restreindre au proxy/healthcheck.
SEC-FIX-018 - Documentation securite et environnement
Statut: non corrige
Preuve dans le code:
README.mdet.env.examplesont absents.AGENTS.md:66,CLAUDE.md:171etdocs/backend.md:5-12decrivent encore les routeurs metier avecget_current_userau lieu derequire_password_changed.docs/backend.md:28-36ne reflete pas le nouveau champmust_change_passwordni les erreurs de validation.
Risque restant:
- Operateur guide par une documentation obsolete, avec configuration dev/prod et secrets insuffisamment explicites.
Recommandation finale:
- Ajouter
README.mdet.env.example, puis mettre a jourAGENTS.md,CLAUDE.mdetdocs/*pourINITIAL_ADMIN_PASSWORD,SECRET_KEY, CORS, TLS, rotation de cle, sauvegarde/restauration et profils dev/prod.
Conclusion
Les trois corrections declarees sont globalement integrees, mais seules SEC-FIX-002 peut etre consideree corrigee avec des risques residuels acceptables pour le mode Compose actuel. SEC-FIX-001 et SEC-FIX-003 restent partielles. Les autres taches du plan ne sont pas encore appliquees.
Priorite recommandee:
- Corriger la migration/strategie de rattrapage pour les comptes existants
admin. - Mettre a jour la documentation et ajouter
.env.example. - Ajouter des tests API pour auth, rate limit et changement force.
- Continuer les corrections P1 restantes: JWT/session, discovery, validation metier et secret JWT.