Qué es un puerto y cómo saber qué escucha en Linux
Entiende los puertos TCP y UDP, el rango 1-65535 y la diferencia entre puertos locales y públicos. Usa ss para ver qué servicios están escuchando en Linux.
Qué es realmente un puerto
Un puerto es un número que permite que un servidor ejecute varios servicios a la vez sin mezclar su tráfico. Tu VPS tiene una dirección IP, pero puede ejecutar al mismo tiempo un servidor web, un servidor SSH y una base de datos. Cuando llega un paquete, el sistema operativo necesita saber para cuál de ellos es. El número de puerto proporciona esa información. El tráfico HTTPS normalmente llega al puerto 443 y el tráfico SSH, al puerto 22. La dirección IP lleva el paquete hasta tu servidor; el puerto lo entrega al programa correcto de ese servidor.
Un puerto es un número de 16 bits: 16 bits proporcionan los valores de 0 a 65535, y el 0 está reservado, por lo que en la práctica los puertos van del 1 al 65535. Los puertos inferiores a 1024 son los puertos «bien conocidos» y, de forma predeterminada, Linux sólo permite que root (o un programa al que se haya concedido la capacidad CAP_NET_BIND_SERVICE) los abra. Por eso los servicios estándar usan esos puertos: 22 para SSH, 80 para HTTP, 443 para HTTPS y 53 para DNS. El sysctl net.ipv4.ip_unprivileged_port_start puede cambiar ese límite, pero su valor predeterminado es 1024. Cualquier puerto a partir de 1024 está disponible para los programas ordinarios.
Hay dos tipos: TCP y UDP. El número de puerto de uno es independiente del mismo número en el otro. TCP es el protocolo orientado a conexión que usan la mayoría de los servicios, como SSH, HTTP y las bases de datos. UDP no usa conexión y se emplea para servicios como DNS y algunas VPN. Al abrir un puerto en el firewall, normalmente se especifica cuál de los dos protocolos se aplica, por ejemplo 22/tcp.
Escuchar significa que un programa espera conexiones en un puerto
Un programa que quiere recibir conexiones pide al kernel que «escuche» en un puerto. Desde ese momento, el puerto está abierto en la máquina y el programa responde a todo lo que llega allí, según las reglas del firewall. Un puerto en el que no escucha ningún programa simplemente rechaza las conexiones. Por eso, la primera pregunta de cualquier comprobación de seguridad es: qué está escuchando y dónde.
El comando para responder a esa pregunta es ss:
sudo ss -tlnpLas opciones indican TCP (t), sólo sockets en escucha (l), puertos numéricos (n, por lo que verá 22 en lugar de ssh) y el proceso propietario (p). Un resultado habitual:
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 columna Process indica qué programa es el propietario de cada puerto. Así puede localizar algo que no tenía intención de dejar en ejecución.
La columna Local Address es la parte importante
Lea con atención la dirección que aparece delante de cada puerto, porque determina quién puede acceder al servicio. Hay tres casos que verá constantemente.
0.0.0.0:22 significa «escuchar en todas las direcciones IPv4 que tiene esta máquina», incluida la dirección pública. El servicio es accesible desde Internet mediante IPv4, siempre que el firewall lo permita.
[::]:80 significa lo mismo para IPv6: escuchar en todas las direcciones IPv6, incluidas las públicas. Muchos programas se enlazan aquí de forma predeterminada y, en Linux, un socket :: también suele aceptar IPv4.
127.0.0.1:5432 significa «escuchar sólo en loopback». 127.0.0.1 es la dirección que usa una máquina para comunicarse consigo misma y, con la configuración predeterminada del kernel, no se puede enrutar desde ningún otro lugar. Un servicio enlazado a esta dirección sólo es accesible desde el mismo servidor, no desde Internet, aunque el firewall permita el puerto. La línea de Postgres anterior es segura de forma predeterminada. La excepción es un ajuste del kernel llamado route_localnet: está desactivado de forma predeterminada, pero algunas herramientas lo activan (kube-proxy de Kubernetes lo hace) y, junto con las reglas de enrutamiento o NAT adecuadas, permite que el tráfico de loopback llegue desde el exterior. sysctl -a | grep route_localnet debería mostrar = 0 en todas las líneas.
La regla práctica se deduce directamente de esto: una base de datos, una caché o un panel de administración que sólo usan tus propias aplicaciones debe enlazarse a 127.0.0.1, no a 0.0.0.0. Si nunca escucha en una dirección pública, no hay nada a lo que pueda acceder un atacante.
Escuchar no equivale a ser accesible
Hay otra diferencia que evita muchas confusiones. Que un puerto esté abierto en la máquina, es decir, que un programa esté escuchando, no es lo mismo que que se pueda acceder a ese puerto desde el exterior, es decir, que el firewall permita el tráfico. Ambas condiciones deben cumplirse para que un cliente remoto pueda conectarse. Además, los dos fallos se ven de forma distinta desde el cliente: una conexión rechazada suele indicar que no había ningún proceso escuchando, mientras que una conexión que queda bloqueada y finalmente agota el tiempo de espera suele indicar que un firewall descartó el paquete. Eso es exactamente lo que indican esos dos errores de SSH.
Por tanto, hay dos capas de control. Usted decide qué escucha configurando la dirección de enlace de cada servicio. También decide a qué puede acceder el exterior mediante un firewall. Un servidor bien administrado usa ambas capas: los servicios se enlazan sólo donde lo necesitan y el firewall deniega todo lo que no se haya permitido explícitamente. Leer qué está escuchando con ss es el primer paso; decidir qué permite el firewall es el segundo, como se explica en introducción a los firewalls con UFW.
Aquí hay un detalle sutil que causa problemas. IPv4 e IPv6 son independientes, y un firewall que sólo cubre IPv4 deja abiertos los servicios [::] en IPv6. Este caso concreto se explica en la trampa del firewall de IPv6.
FAQ
¿Cómo puedo ver qué puertos están abiertos en mi servidor Linux?
Ejecute sudo ss -tlnp para TCP o sudo ss -ulnp para UDP. Esto muestra todos los sockets que están escuchando, el puerto, la dirección local a la que están enlazados y el proceso propietario. Lea la columna Local Address: 0.0.0.0 o [::] significa que el servicio está expuesto a la red, mientras que 127.0.0.1 significa que sólo escucha en la propia máquina.
¿Cuál es la diferencia entre 0.0.0.0 y 127.0.0.1?
0.0.0.0 significa «escuchar en todas las direcciones IPv4», incluida la pública, por lo que se puede acceder al servicio desde la red. 127.0.0.1 es loopback, la dirección que usa la máquina para comunicarse consigo misma y que, con la configuración predeterminada del kernel, no se puede enrutar desde ningún otro lugar. Por tanto, un servicio enlazado a ella sólo es accesible localmente. Enlace los servicios internos a 127.0.0.1 para mantenerlos fuera de la red.
¿Necesito abrir un puerto en el firewall para que funcione un servicio?
Sólo para los servicios a los que deban acceder otras máquinas. Un servicio enlazado a 127.0.0.1 no necesita una regla de permiso, porque, con la configuración predeterminada del kernel, nada externo puede acceder a él. Un servicio en 0.0.0.0 o [::] necesita una regla de permiso cuando el firewall deniega por defecto el tráfico entrante, como debería hacer. Si no hay ningún firewall activo o su política acepta todo, ese servicio ya es accesible sin ninguna regla.
¿Cuál es la diferencia entre un puerto TCP y un puerto UDP?
TCP está orientado a conexión y lo usan la mayoría de los servicios, como SSH, los servidores web y las bases de datos. UDP no usa conexión y se emplea para DNS y algunas VPN. El mismo número en TCP y UDP corresponde a puertos distintos, por lo que 53/tcp y 53/udp son diferentes. Al escribir reglas de firewall se especifica el protocolo, por ejemplo 22/tcp.