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>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
# 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
|
||||
|
||||
```yaml
|
||||
# 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 |
|
||||
Reference in New Issue
Block a user