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>
7.1 KiB
Security Fixes Applied — Phase 3
Date: 2026-05-06
SEC-FIX-006 — Validation des entrées discovery
Problème
dns_serveracceptait n'importe quelle chaîne (risque d'injection dans le résolveur DNS)/api/discovery/pingacceptait n'importe quelle chaîne comme IP (transmise au sous-processus ping)- Plusieurs targets pouvaient contourner le cap de 1024 : 5 × /22 = 5110 hôtes
Corrections appliquées
backend/routers/discovery.py
ScanRequest.dns_server:field_validatorqui appelleipaddress.ip_address(v)— rejette toute valeur non-IP (422)PingRequest.ips:field_validatorqui valide chaque IP — rejette toute entrée malformée avant d'appeler le sous-processus (422)MAX_HOSTS_TOTAL = 4096: cap global sur la somme des hôtes de tous les targets — rejette si dépassé (400)
SEC-FIX-007 — Validation Pydantic métier
Problème
Aucun validator sur les schémas métier : valeurs hors-domaine, CIDR invalides, couleurs arbitraires, URLs arbitraires, IPs invalides, types inconnus acceptés silencieusement.
Corrections appliquées
backend/routers/vlans.py
vlan_id: 1–4094 (norme 802.1Q)name: non vide, max 100 caractères (strip)cidr:ipaddress.ip_network(strict=False)si non videcolor: regex^#[0-9a-fA-F]{6}$
backend/routers/devices.py
name: non vide, max 100 caractères (strip)description: max 500 caractèrestype: enum des 18 types validesvirt_type: enum{null, baremetal, lxc, qemu}url:urlparse— schémahttp/https+ netloc non videInterfaceCreate.name: non vide, max 50 caractèresInterfaceCreate.ip_address:ipaddress.ip_address(v)si non vide
Toutes les erreurs de validation retournent 422 (comportement standard FastAPI/Pydantic).
SEC-FIX-008 — En-têtes HTTP sécurité Nginx
Problème
Aucun en-tête de sécurité HTTP : pas de CSP, pas de protection contre le MIME sniffing ou le framing.
Corrections appliquées
frontend/nginx.conf
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'self';
Tous les en-têtes utilisent le flag always pour s'appliquer aussi aux réponses d'erreur.
SEC-FIX-009 — Documentation TLS/HTTPS
Statut : CORRIGÉ EN PHASE 2/3
Documentation ajoutée au README.md lors de la session précédente :
- Section HTTPS avec exemple nginx reverse-proxy complet
docker-compose.override.ymlpour limiter l'exposition au loopback
SEC-FIX-012 — Logs d'audit structurés
Problème
Aucune trace des événements d'authentification : connexions, échecs, changements de mot de passe.
Corrections appliquées
backend/routers/auth.py
- Logger stdlib
logging.getLogger("audit")— aucune dépendance supplémentaire - Helper
_log_audit(event, **kw): émet une ligne JSON{"event": ..., "ts": ..., ...} - Événements loggés :
auth.login.success— username, ipauth.login.failure— username, ipauth.login.rate_limited— ip, username (si disponible), reason (ip|username)auth.token_rejected— username, reason (user_not_found|version_mismatch)auth.account.password_changed— usernameauth.account.username_changed— old_username, new_usernameauth.account.bad_password— username
Activation dans Docker via la config de logging uvicorn (stdout par défaut).
SEC-FIX-013 — PRAGMA foreign_keys=ON
Problème
SQLite désactive les contraintes de clés étrangères par défaut. Les suppressions en cascade ne sont pas enforced.
Corrections appliquées
backend/database.py
@event.listens_for(Engine, "connect")
def _set_sqlite_pragma(dbapi_conn, _record):
if isinstance(dbapi_conn, sqlite3.Connection):
cursor = dbapi_conn.cursor()
cursor.execute("PRAGMA foreign_keys=ON")
cursor.close()
Le listener s'exécute sur chaque nouvelle connexion SQLite, y compris les connexions de test.
SEC-FIX-014 — Dépendance cytoscape non utilisée
Statut : CORRIGÉ EN PHASE 2
cytoscape supprimé de frontend/package.json lors de la session précédente.
SEC-FIX-015 — Import JSON sans limite de taille ni validation de schéma
Problème
Un fichier JSON de plusieurs gigaoctets pouvait être chargé en mémoire. Aucune validation du schéma avant traitement.
Corrections appliquées
frontend/src/App.vue
- Vérification
file.size > 5 * 1024 * 1024avantfile.text()— rejette avec message localisé - Validation de schéma :
- Le JSON doit être un objet (pas un tableau, pas null)
vlansetdevices, si présents, doivent être des tableaux
frontend/src/i18n.js
- Clé
importTooLargeajoutée (fr, en, es)
SEC-FIX-016 — v-html dans App.vue
Problème
v-html utilisé pour injecter des entités HTML (■, ◆, ▣) dans les boutons de navigation. Risque XSS si la source venait à être dynamique.
Corrections appliquées
frontend/src/App.vue
- Entités HTML remplacées par leurs équivalents Unicode directs (
■,◆,▣) v-html="tab.icon"remplacé par{{ tab.icon }}(interpolation texte — échappe automatiquement)
SEC-FIX-017 — Nettoyage du code orphelin Links (backend)
Problème
La vue Liens avait été retirée du frontend en phase 2/3, mais le backend conservait :
backend/routers/links.py— router toujours enregistré dans main.pyclass Linkdansmodels.py— ORM orphelin- Référence explicite à
models.Linkdansdelete_device(devices.py) - La table
linksen base — avec FK versdevices, ce qui bloquerait les suppressions d'équipements avecPRAGMA foreign_keys=ON
Corrections appliquées
backend/routers/links.py — Supprimé
backend/models.py — Classe Link supprimée
backend/routers/devices.py — Suppression de la requête db.query(models.Link).filter(...).delete() dans delete_device
backend/main.py
- Import
linksretiré app.include_router(links.router, ...)retiré- Nouvelle migration
_migrate_drop_links_table(): DROP TABLE links si elle existe (avecPRAGMA foreign_keys=OFF/ONpour éviter les erreurs FK pendant la migration)
Fichiers modifiés
| Fichier | Fix(es) |
|---|---|
backend/database.py |
SEC-FIX-013 |
backend/models.py |
SEC-FIX-017 |
backend/main.py |
SEC-FIX-017 |
backend/routers/auth.py |
SEC-FIX-012 |
backend/routers/vlans.py |
SEC-FIX-007 |
backend/routers/devices.py |
SEC-FIX-007, SEC-FIX-017 |
backend/routers/discovery.py |
SEC-FIX-006 |
backend/routers/links.py |
SEC-FIX-017 (supprimé) |
backend/tests/test_validation.py |
Tests SEC-FIX-006, 007, 013, 017 (nouveau) |
frontend/nginx.conf |
SEC-FIX-008 |
frontend/src/App.vue |
SEC-FIX-015, SEC-FIX-016 |
frontend/src/i18n.js |
SEC-FIX-015 |