Principe du tunnel

Le tunnel repose sur le ssh -R 0:localhost:8080 web02.luffy.cx. En spécifiant 0 comme port distant, le serveur SSH alloue un port libre – dans l’exemple 41535. Cette allocation provient de la plage 32768‑60999, soit environ 14,8 bits d’entropie, ce qui limite la robustesse contre l’énumération.

Configuration Nginx et DNS

Un serveur Nginx écoute sur le port 443 en SSL et utilise une expression régulière pour extraire le port alloué depuis le sous‑domaine p<port>.ssh.luffy.cx. Le bloc suivant montre la configuration :

server {
    listen 0.0.0.0:443 ssl;
    listen [::0]:443 ssl;
    server_name ~ ^p(?\d{5})\.ssh\.luffy\.cx$;
    location / {
        proxy_pass http://127.0.0.1:$port;
    }
}

Un enregistrement CNAME *.ssh.luffy.cx → web02.luffy.cx et un certificat générique *.ssh.luffy.cx délivré par Let’s Encrypt (via ACME DNS‑01 sur Route 53) permettent le chiffrement sans intervention manuelle.

Mécanisme de sécurisation

Le module ngx_http_secure_link_module ajoute une couche d’authentification basée sur un hash MD5. Le hash combine trois valeurs : l’horodatage d’expiration, le port alloué et le secret ZuPerS3cr3!. Le client transmet le hash et l’expiration dans le champ username de l’authentification HTTP basique, par exemple :

https://6J3jK1WmB15c6WmjW_X-Wg--1789928654@p41535.ssh.luffy.cx/…

Le map suivant extrait les deux parties et les reformate pour secure_link :

map $remote_user $httpssh_link {
    "~^([-_A-Za-z0-9]{22})--([0-9]+)$" "$1,$2";
}

Le résultat de la vérification se trouve dans $secure_link : vide → 401, 0 → 410, 1 → accès autorisé. Le code complet gère également les en‑têtes, le support WebSocket et désactive le buffering pour des flux longs.

Script d’identification du port

OpenSSH ne transmet pas le port alloué au client. Le script proposé parcourt les processus sshd-session (ou sshd avant la version 9.8) pour récupérer les sockets associés. Il nécessite sudo car le processus a perdu les privilèges et son répertoire /proc/PID/fd appartient à root.

pids=$(pid=$$
while [ "$pid" -gt 1 ]; do
  line=$(ps -o comm=,pid=,ppid= -p "$pid")
  echo "$line"
  pid=${line##* }
done | awk '$1 == "sshd-session" {printf "pid=%s,\n", $2}')

if [ -z "$pids" ]; then echo "not an ssh session" >&2; exit 1; fi

# ensuite, ss -lpn | grep $pids pour extraire le port

Cette approche fonctionne tant que le serveur exécute OpenSSH ≥ 9.8 et que l’administrateur accepte l’usage de sudo. Les limites restent la faible entropie du port, la dépendance à MD5 et le besoin de privilèges élevés pour le script.