HTTP en profondeur - 15 - Proxy : forward, reverse et les headers qui trahissent

Forward proxy, reverse proxy, X-Forwarded-For, X-Real-IP, Via et comment Caddy ou Nginx gerent tout ca.

15 - Proxy : forward, reverse et les headers qui trahissent

Ce que tu vas apprendre

  • La différence entre forward proxy et reverse proxy
  • Les headers X-Forwarded-For, X-Real-IP et Via
  • Comment configurer Caddy ou Nginx en reverse proxy
  • Le Proxy Protocol et pourquoi il existe

Prerequisites


Le mot "proxy" revient tout le temps. Dans les docs, dans les configs, dans les conversations entre devs. Et pourtant, je croise régulièrement des gens qui confondent forward proxy et reverse proxy. Ou qui ne savent pas pourquoi leur appli voit toujours 127.0.0.1 comme IP client. On va demystifier tout ca.

Forward proxy : le proxy cote client

Un forward proxy se place entre le client et Internet. C'est le client qui sait qu'il passe par un proxy. Le serveur de destination, lui, ne voit que l'IP du proxy.

Client --> Forward Proxy --> Internet --> Serveur

Cas d'usage classiques :

  • Proxy d'entreprise : ta boîte filtre le trafic sortant. Tu ne peux pas aller sur Twitter pendant les heures de bureau (en theorie).
  • Anonymisation : le serveur ne voit pas ton IP réelle. C'est le principe de base d'un VPN grand public.
  • Cache partage : Squid en entreprise qui met en cache les telechargements pour éviter de pomper la bande passante.

Le navigateur ou le système d'exploitation est configure explicitement pour utiliser le proxy. La requête HTTP ressemble a ca :

httpGET http://example.com/page HTTP/1.1
Host: example.com

Note que l'URL dans la ligne de requête est absolue. C'est comme ca que le proxy sait ou envoyer la requête.

Reverse proxy : le proxy cote serveur

Un reverse proxy se place devant tes serveurs. Le client ne sait meme pas qu'il existe. Il pense parler directement a ton appli, mais en réalité il parle a Nginx, Caddy, HAProxy ou un load balancer cloud.

Client --> Reverse Proxy --> Serveur(s) applicatif(s)

Cas d'usage :

  • Load balancing : repartir le trafic entre plusieurs instances de ton appli
  • Terminaison SSL : le reverse proxy gere le certificat TLS, ton appli recoit du HTTP en clair en interne
  • Compression et cache : gzip/brotli applique au niveau du proxy
  • Protection : rate limiting, WAF, filtrage avant que la requête touche ton code

Si tu deploies une appli en production, tu as un reverse proxy. Meme si tu ne le sais pas. Vercel, Cloudflare, AWS ALB : ce sont tous des reverse proxies.

Les headers qui racontent l'histoire

Quand une requête passe par un proxy, l'IP source change. Ton appli ne voit plus le vrai client. C'est la que les headers proxy entrent en jeu.

X-Forwarded-For

Le grand classique. Chaque proxy ajoute l'IP du hop précédent :

httpX-Forwarded-For: 203.0.113.50, 70.41.3.18, 150.172.238.178

La première IP est (en theorie) le client original. Les suivantes sont les proxies intermediaires. Je dis "en theorie" parce que n'importe qui peut forger ce header. Ne fais jamais confiance a X-Forwarded-For sans savoir combien de proxies tu as devant toi.

X-Real-IP

Plus simple : une seule IP, celle du client original. Souvent positionne par le premier reverse proxy de la chaîne. Nginx l'utilise beaucoup.

httpX-Real-IP: 203.0.113.50

Via

Le header Via est défini dans la spec HTTP. Il trace la chaîne de proxies :

httpVia: 1.1 proxy1.example.com, 1.1 proxy2.example.com

Le format est version pseudo. En pratique, je le vois moins souvent que X-Forwarded-For, mais il a le merite d'etre standardise.

Forwarded (le standard moderne)

La RFC 7239 a introduit un header propre pour remplacer tout le bazar X- :

httpForwarded: for=203.0.113.50;proto=https;by=proxy1.example.com

L'adoption est lente. La plupart des outils utilisent encore les X-Forwarded-*.

Caddy en reverse proxy

Caddy est mon choix par défaut pour un reverse proxy. La config est ridiculement simple :

app.example.com {
    reverse_proxy localhost:3000
}

C'est tout. Caddy gere automatiquement le certificat Let's Encrypt, le renouvellement, la terminaison TLS, les headers X-Forwarded-For et X-Forwarded-Proto. Sur paltemps.fr, c'est exactement cette config (ou presque) qui tourne.

Pour du load balancing :

app.example.com {
    reverse_proxy localhost:3000 localhost:3001 localhost:3002 {
        lb_policy round_robin
        health_uri /health
        health_interval 10s
    }
}

Nginx en reverse proxy

Nginx demande plus de configuration, mais offre un contrôle plus fin :

nginxserver {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate /etc/ssl/cert.pem;
    ssl_certificate_key /etc/ssl/key.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Si tu oublies les proxy_set_header, ton appli verra 127.0.0.1 comme IP client et http comme protocole. Un classique.

Le Proxy Protocol

Les headers HTTP c'est bien, mais ils ont un problème : ils fonctionnent uniquement pour du HTTP. Si tu proxifies du TCP brut (une base de donnees, du SMTP, du WebSocket sans upgrade HTTP), tu n'as pas de headers.

Le Proxy Protocol (invente par HAProxy) resout ca. C'est une ligne de texte ajoutee au début de la connexion TCP :

PROXY TCP4 203.0.113.50 10.0.0.1 56324 443

Version 2 utilise un format binaire plus efficace. Nginx, HAProxy, Caddy, AWS NLB supportent tous le Proxy Protocol. Mais attention : le serveur de destination doit le supporter aussi, sinon il va interpréter cette ligne comme des donnees corrompues.

Le piège de la confiance

Un point que je vois mal gere partout : la confiance dans les headers proxy.

Si ton appli fait du rate limiting base sur X-Forwarded-For, un attaquant peut simplement envoyer :

httpX-Forwarded-For: 1.2.3.4

Et changer d'IP a chaque requête. La solution : configure ton reverse proxy pour ecraser le header X-Forwarded-For entrant et ne garder que ce qu'il voit lui-meme. Ou mieux, utilise le Proxy Protocol.

Résumé

  • Un forward proxy est cote client (cache, filtrage, anonymisation)
  • Un reverse proxy est cote serveur (load balancing, SSL, protection)
  • X-Forwarded-For donne la chaîne d'IPs, mais ne lui fais pas confiance aveuglément
  • X-Real-IP donne une seule IP, posee par le premier proxy
  • Caddy gere tout automatiquement, Nginx demande de la config manuelle
  • Le Proxy Protocol fonctionne au niveau TCP, pas HTTP

Article précédent : 14 - Redirections Article suivant : 16 - HTTP/2

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.