chore(ideai): ouverture de #72 (confiance reverse proxy sans effet réel)
- #72 ouvert en priorité haute, bloquant #68 : `--trust-reverse-proxy` n'est lu que dans `ServerConfig::validate()` pour exiger sa propre présence — le serveur ne parse jamais `X-Forwarded-*`. C'est un drapeau d'intention pur, qui donne un faux sentiment de protection. Le ticket porte aussi B0 (le bug de port effectif sur le chemin CLI `run_server`), `trusted_proxies` + `--trusted-proxy`, le guard runtime et les événements de diagnostic. - Journal des tâches de fond : complétions enregistrées. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
6
.ideai/tickets/72/carnet.md
Normal file
6
.ideai/tickets/72/carnet.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
issueRef: "#72"
|
||||
version: 1
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedAt: 1784218596269
|
||||
---
|
||||
53
.ideai/tickets/72/issue.md
Normal file
53
.ideai/tickets/72/issue.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
id: "0fba0a7f-8f04-460e-b81a-93790e10b066"
|
||||
number: 72
|
||||
title: "Sécurité : donner un effet réel à la confiance reverse proxy (--trust-reverse-proxy est un drapeau creux)"
|
||||
status: "open"
|
||||
priority: "high"
|
||||
sprint: null
|
||||
links: [{"target":"#68","kind":"blocks"},{"target":"#71","kind":"relatesTo"},{"target":"#65","kind":"relatesTo"}]
|
||||
agentRefs: []
|
||||
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
|
||||
createdAt: 1784218596269
|
||||
updatedAt: 1784218596269
|
||||
version: 1
|
||||
---
|
||||
**Vulnérabilité de conception existante, dans le mode CLI d'aujourd'hui — indépendante de #68.** Trouvée par Git pendant la mise en place de #68, confirmée et cadrée par Architect.
|
||||
|
||||
**Le constat.** `--trust-reverse-proxy` n'a **aucun effet à l'exécution**. Vérifié dans `crates/web-server/src/lib.rs` : le champ n'est lu qu'en ligne 192, dans `ServerConfig::validate()`, **pour exiger sa propre présence** quand `allow_remote` est vrai. Le serveur ne parse jamais `X-Forwarded-*`. C'est un drapeau d'intention pur.
|
||||
|
||||
**Le problème.** `validate()` valide une configuration, pas la réalité : rien ne vérifie qu'un proxy est réellement devant le serveur. **Binder `0.0.0.0` avec les trois drapeaux, sans aucun proxy, satisfait `validate()` et sert du HTTP en clair au monde entier.** La trilogie `allow_remote` + origine HTTPS + `trust_reverse_proxy` DÉCLARE une topologie sécurisée, elle ne la GARANTIT pas.
|
||||
|
||||
Verdict Architect : « la trilogie actuelle n'est pas un invariant de sécurité, c'est seulement une déclaration d'intention ». Aggravé par #68 : en CLI, taper trois drapeaux est un acte délibéré d'opérateur ; dans un panneau desktop, cocher un bouton ne l'est pas. Le drapeau donnerait un faux sentiment de protection en un clic.
|
||||
|
||||
**Invariant runtime corrigé (Architect).**
|
||||
- `allow_remote=true` signifie : mode public accepté UNIQUEMENT derrière un proxy HTTPS déclaré.
|
||||
- Les headers `X-Forwarded-*` ne sont fiables QUE si le `peer_addr` réseau est un proxy autorisé — vérifier le pair AVANT de leur faire confiance.
|
||||
- `X-Forwarded-Proto: https` exigé en mode remote.
|
||||
- `X-Forwarded-Host` (ou équivalent) doit correspondre à `public_origin`.
|
||||
- **`X-Forwarded-For` ne doit JAMAIS servir à autoriser une requête** — spoofable, log uniquement.
|
||||
- Proxy sur cette machine : bind loopback, peer forcément loopback, `trust_reverse_proxy` reste acceptable.
|
||||
- Proxy sur une autre machine : bind LAN autorisé SEULEMENT avec un proxy explicite (`--trusted-proxy 192.168.1.10` ou CIDR). Toute requête dont le `peer_addr` est hors allowlist est refusée, même porteuse de `X-Forwarded-Proto: https`.
|
||||
|
||||
Conséquence produit : le mode desktop « proxy autre machine » **ne peut pas être un clic magique**. Il doit demander l'IP/CIDR du proxy autorisé — ce n'est pas une « listen address » mais un contrôle de sécurité compréhensible : « quelle machine a le droit de parler au serveur IdeA ? ».
|
||||
|
||||
**Lots (Architect).**
|
||||
- **B1 config** : `trusted_proxies: Vec<IpNet/Cidr>` dans `ServerConfig`, flag CLI `--trusted-proxy`, DTO desktop équivalent.
|
||||
- **B2 runtime guard** : en tête du handling HTTP/WS, vérifier `peer_addr`, `X-Forwarded-Proto=https`, host public conforme.
|
||||
- **B3 diagnostics** : événements `untrustedProxyPeer`, `forwardedProtoRejected`, `forwardedHostRejected` (à croiser avec #71).
|
||||
- **B4 docs** : exemples séparés proxy local vs proxy autre machine.
|
||||
|
||||
**Points de vérité QA.**
|
||||
- `0.0.0.0 + allow_remote + public_origin + trust_reverse_proxy` sans trusted proxy → REFUSÉ.
|
||||
- peer non autorisé vers bind LAN → rejeté.
|
||||
- peer autorisé mais `X-Forwarded-Proto=http` → rejeté.
|
||||
- peer autorisé + https + host conforme → passe.
|
||||
- origine API non conforme → toujours 403.
|
||||
- aucun test ne fait confiance à `X-Forwarded-For`.
|
||||
|
||||
**Compat / migration.** Garder `--trust-reverse-proxy` pour la CLI, mais le déclasser en option de mode : il ne suffit plus pour un bind non-loopback. Chemin de migration à choisir (refus au démarrage vs refus runtime).
|
||||
|
||||
⚠️ **Impact utilisateur réel connu** : l'installation actuelle de l'utilisateur (bind `192.168.1.75:17373` + trilogie, proxy sur une autre machine, exposé via `https://idea.anthonybouteiller.ovh`) sera **refusée** par la validation corrigée tant qu'elle ne déclare pas `--trusted-proxy`. Le chemin de migration doit être explicite et le message d'erreur doit dire quoi faire, pas seulement refuser.
|
||||
|
||||
**Ordre imposé par Architect** : #68 core (B1 shared-core) peut continuer, il n'est pas exposé utilisateur. Mais **#72 doit être mergé dans `develop` AVANT `feature/ticket68-embedded-server-panel`** — pas de panneau remote avant ce durcissement.
|
||||
@ -1,3 +1,3 @@
|
||||
{
|
||||
"nextNumber": 72
|
||||
"nextNumber": 73
|
||||
}
|
||||
@ -748,6 +748,16 @@
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784210443885
|
||||
},
|
||||
{
|
||||
"issueRef": "#72",
|
||||
"path": "72",
|
||||
"title": "Sécurité : donner un effet réel à la confiance reverse proxy (--trust-reverse-proxy est un drapeau creux)",
|
||||
"status": "open",
|
||||
"priority": "high",
|
||||
"sprint": null,
|
||||
"assignedAgentIds": [],
|
||||
"updatedAt": 1784218596269
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user