Ports Linux : comprendre les services en écoute
Comprenez les ports TCP et UDP, puis utilisez ss pour voir les services en écoute et distinguer un port local d’un port exposé publiquement.
Ce qu’est réellement un port
Un port est un numéro qui permet à un serveur d’exécuter plusieurs services simultanément sans mélanger leur trafic. Votre VPS possède une seule adresse IP, mais il peut exécuter en même temps un serveur web, un serveur SSH et une base de données. Lorsqu’un paquet arrive, le système d’exploitation doit savoir à quel service il est destiné. Le numéro de port fournit cette information. Le trafic HTTPS arrive normalement sur le port 443 et le trafic SSH sur le port 22. L’adresse IP achemine le paquet jusqu’à votre serveur ; le port l’achemine jusqu’au bon programme sur ce serveur.
Un port est un nombre codé sur 16 bits : 16 bits donnent les valeurs 0 à 65535, et 0 est réservé. En pratique, les ports vont donc de 1 à 65535. Les ports inférieurs à 1024 sont les ports « bien connus ». Par défaut, Linux permet uniquement à root (ou à un programme auquel la capability CAP_NET_BIND_SERVICE a été accordée) de les ouvrir. C’est pourquoi les services standard les utilisent : 22 pour SSH, 80 pour HTTP, 443 pour HTTPS et 53 pour DNS. Le sysctl net.ipv4.ip_unprivileged_port_start peut modifier cette limite, mais sa valeur par défaut est 1024. À partir de 1024, les ports peuvent être utilisés par les programmes ordinaires.
Il existe deux types de ports : TCP et UDP. Un numéro de port TCP est distinct du même numéro en UDP. TCP est le protocole orienté connexion utilisé par la plupart des services, notamment SSH, HTTP et les bases de données. UDP est sans connexion et sert notamment pour DNS et certains VPN. Lorsque vous ouvrez un port dans un firewall, vous indiquez généralement le protocole concerné, par exemple 22/tcp.
Écouter signifie qu’un programme attend sur un port
Un programme qui doit recevoir des connexions demande au noyau d’« écouter » sur un port. À partir de ce moment, le port est ouvert sur la machine et le programme répond à tout ce qui y arrive, sous réserve des règles du pare-feu. Un port sur lequel aucun programme n’écoute refuse simplement les connexions. La première question à poser lors de tout contrôle de sécurité est donc la suivante : qu’est-ce qui écoute, et où ?
La commande qui permet de le vérifier est ss :
sudo ss -tlnpLes options indiquent qu’il s’agit de TCP (t), qu’il faut afficher uniquement les sockets en écoute (l), utiliser des ports numériques (n, pour afficher 22 et non ssh), et afficher le processus propriétaire (p). Exemple de résultat :
State Recv-Q Local Address:Port Process
LISTEN 0 0.0.0.0:22 sshd
LISTEN 0 127.0.0.1:5432 postgres
LISTEN 0 [::]:80 nginxLa colonne Process indique quel programme possède chaque port. Elle permet d’identifier un service que vous n’aviez pas prévu de laisser actif.
La colonne Local Address est l’élément important
Lisez attentivement l’adresse affichée devant chaque port, car elle détermine qui peut atteindre le service. Vous rencontrerez constamment trois cas.
0.0.0.0:22 signifie « écouter sur toutes les adresses IPv4 de cette machine », y compris son adresse publique. Le service est alors accessible depuis Internet en IPv4, si le firewall l’autorise.
[::]:80 signifie la même chose pour IPv6 : écouter sur toutes les adresses IPv6, y compris les adresses publiques. De nombreux programmes se bindent ici par défaut. Sous Linux, un socket :: accepte souvent aussi les connexions IPv4.
127.0.0.1:5432 signifie « écouter uniquement sur loopback ». 127.0.0.1 est l’adresse qu’une machine utilise pour communiquer avec elle-même. Avec les paramètres par défaut du kernel, elle n’est pas routable depuis l’extérieur. Un service bindé sur cette adresse est donc accessible uniquement depuis le même serveur, et non depuis Internet, même si votre firewall autorise le port. La ligne Postgres présentée plus haut est sûre par défaut. Il existe toutefois une exception : le paramètre du kernel appelé route_localnet. Il est désactivé par défaut, mais certains outils l’activent, notamment kube-proxy de Kubernetes. Avec ce paramètre et les règles de routage ou de NAT appropriées, du trafic loopback peut alors arriver de l’extérieur. sysctl -a | grep route_localnet doit afficher = 0 sur chaque ligne.
La règle pratique en découle directement : une base de données, un cache ou un panneau d’administration utilisé uniquement par vos propres applications doit se binder sur 127.0.0.1, et non sur 0.0.0.0. S’il n’écoute jamais sur une adresse publique, un attaquant n’a rien à atteindre.
Écouter ne signifie pas être accessible
Une distinction supplémentaire évite beaucoup de confusion. Un port ouvert sur la machine, c’est-à-dire un port sur lequel un programme écoute, n’est pas nécessairement accessible depuis l’extérieur, c’est-à-dire autorisé par le firewall. Les deux conditions doivent être réunies pour qu’un client distant puisse se connecter. Les deux échecs produisent même des symptômes différents côté client : une connexion refusée signifie généralement qu’aucun programme n’écoutait, tandis qu’une connexion qui reste bloquée puis expire indique généralement que le firewall a abandonné le paquet. C’est exactement ce que signifient ces deux erreurs SSH.
Il existe donc deux niveaux de contrôle. Vous choisissez ce qui écoute en configurant l’adresse de bind de chaque service. Vous choisissez ensuite ce que le monde extérieur peut atteindre avec un firewall. Un serveur correctement administré utilise les deux mécanismes : les services se bindent uniquement là où c’est nécessaire, et le firewall refuse tout ce que vous n’avez pas explicitement autorisé. Vérifier ce qui écoute avec ss constitue la première étape. Déterminer ce que le firewall autorise constitue la deuxième, expliquée dans les bases des firewalls avec UFW.
Un point subtil pose souvent problème ici. IPv4 et IPv6 sont séparés. Un firewall qui ne couvre que l’IPv4 laisse les services [::] ouverts en IPv6. Ce piège précis fait l’objet d’un article dédié : le piège du firewall IPv6.
FAQ
Comment voir les ports ouverts sur mon serveur Linux ?
Exécutez sudo ss -tlnp pour TCP ou sudo ss -ulnp pour UDP. Cette commande affiche chaque socket en écoute, le port, l’adresse locale sur laquelle il est bindé et le processus qui le possède. Lisez la colonne Local Address : 0.0.0.0 ou [::] signifie que le service est exposé au réseau, tandis que 127.0.0.1 signifie qu’il écoute uniquement sur la machine elle-même.
Quelle est la différence entre 0.0.0.0 et 127.0.0.1 ?
0.0.0.0 signifie « écouter sur toutes les adresses IPv4 », y compris l’adresse publique. Le service peut donc être atteint depuis le réseau. 127.0.0.1 est l’adresse loopback utilisée par la machine pour communiquer avec elle-même. Avec les paramètres par défaut du kernel, elle n’est pas routable depuis l’extérieur. Un service bindé sur cette adresse est donc accessible uniquement localement. Bindez les services internes sur 127.0.0.1 afin qu’ils restent hors du réseau.
Dois-je ouvrir un port dans le firewall pour qu’un service fonctionne ?
Uniquement pour les services qui doivent être accessibles depuis d’autres machines. Un service bindé sur 127.0.0.1 n’a besoin d’aucune règle d’autorisation, car avec les paramètres par défaut du kernel, aucun accès externe ne peut l’atteindre. Un service sur 0.0.0.0 ou [::] nécessite une règle d’autorisation lorsque votre firewall refuse par défaut le trafic entrant, ce qui est le comportement recommandé. Si aucun firewall n’est actif ou si sa policy accepte tout, le service est déjà accessible sans aucune règle.
Quelle est la différence entre un port TCP et un port UDP ?
TCP est orienté connexion et utilisé par la plupart des services, notamment SSH, les serveurs web et les bases de données. UDP est sans connexion et utilisé par DNS ainsi que par certains VPN. Le même numéro en TCP et en UDP correspond à deux ports distincts. Ainsi, 53/tcp et 53/udp sont différents. Lorsque vous écrivez des règles de firewall, vous indiquez le protocole, par exemple 22/tcp.