#72 passé en `closed` : mergé dans `develop` via `ae01297`, vert hors sandbox, branche supprimée. Carnet complété avec le périmètre livré et les arbitrages. État `.ideai/` indépendant du code de #68, committé directement sur `develop`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.7 KiB
id, number, title, status, priority, sprint, links, agentRefs, createdBy, updatedBy, createdAt, updatedAt, version
| id | number | title | status | priority | sprint | links | agentRefs | createdBy | updatedBy | createdAt | updatedAt | version | |||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0fba0a7f-8f04-460e-b81a-93790e10b066 | 72 | Sécurité : donner un effet réel à la confiance reverse proxy (--trust-reverse-proxy est un drapeau creux) | closed | high | null |
|
|
|
1784218596269 | 1784236365445 | 3 |
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=truesignifie : mode public accepté UNIQUEMENT derrière un proxy HTTPS déclaré.- Les headers
X-Forwarded-*ne sont fiables QUE si lepeer_addrréseau est un proxy autorisé — vérifier le pair AVANT de leur faire confiance. X-Forwarded-Proto: httpsexigé en mode remote.X-Forwarded-Host(ou équivalent) doit correspondre àpublic_origin.X-Forwarded-Forne doit JAMAIS servir à autoriser une requête — spoofable, log uniquement.- Proxy sur cette machine : bind loopback, peer forcément loopback,
trust_reverse_proxyreste acceptable. - Proxy sur une autre machine : bind LAN autorisé SEULEMENT avec un proxy explicite (
--trusted-proxy 192.168.1.10ou CIDR). Toute requête dont lepeer_addrest hors allowlist est refusée, même porteuse deX-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>dansServerConfig, 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_proxysans 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.