Un firewall (cortafuegos) es un mecanismo de control que inspecciona el tráfico de red entrante y saliente para decidir, paquete a paquete, qué comunicaciones están permitidas y cuáles deben bloquearse según un conjunto ordenado de reglas.
Lejos de ser una caja negra mágica, un firewall opera evaluando metadatos concretos de cada paquete: dirección IP de origen y destino, protocolo (TCP, UDP, ICMP), puerto (como 22 para SSH o 443 para HTTPS) y el estado de la conexión.
§ Filtrado sin estado frente a inspección con estado (*stateful*)
Los primeros cortafuegos analizaban cada paquete de forma aislada (stateless). Hoy en día, el estándar en sistemas operativos y redes es el filtrado con seguimiento de estado (stateful inspection):
Paquete entrante ──► ┌───────────────────────────────┐
│ ¿Pertenece a una conexión │ ── Sí ──► [ ACCEPT ]
│ ya establecida (ESTABLISHED)? │
└───────────────┬───────────────┘
│ No (NEW)
▼
┌───────────────────────────────┐
│ ¿Coincide con alguna regla │ ── Sí ──► [ ACCEPT ]
│ explícita de permiso? │
└───────────────┬───────────────┘
│ No
▼
┌───────────────────────────────┐
│ Política por defecto │ ────────► [ DROP / REJECT ]
└───────────────────────────────┘Esto resuelve un problema fundamental: cuando tu equipo solicita una página web hacia el exterior (conexión saliente), el firewall recuerda esa sesión en su tabla de estados (conntrack en el kernel Linux) y permite automáticamente los paquetes de respuesta de ese servidor sin que tengas que abrir todos los puertos de entrada.
§ Acciones fundamentales: `ACCEPT`, `DROP` y `REJECT`
Cuando un paquete coincide con una regla, el firewall aplica una acción:
| Acción | Comportamiento en la red | Cuándo utilizarla |
|---|---|---|
ACCEPT |
Permite el paso del paquete hacia el proceso o interfaz destino | Servicios legítimos que deben ser accesibles |
DROP |
Descarta el paquete en silencio sin enviar respuesta al emisor | Tráfico externo no solicitado (dificulta el escaneo de puertos) |
REJECT |
Bloquea el paquete pero devuelve un mensaje de error (ICMP o TCP RST) |
Redes internas o depuración donde conviene fallar rápido |
Una configuración segura parte siempre de una política por defecto restrictiva: bloquear todo el tráfico entrante (default deny incoming), permitir el tráfico saliente necesario y abrir únicamente los puertos estrictamente indispensables.
§ Configuración práctica en Linux con `ufw` y `ss`
Antes de escribir reglas en un servidor o estación de trabajo conviene auditar qué servicios están escuchando realmente en la red mediante ss (socket statistics):
ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 511 0.0.0.0:443 0.0.0.0:*
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH administracion'
sudo ufw allow 443/tcp comment 'Servidor HTTPS'
sudo ufw status verbose
Status: active
Default: deny (incoming), allow (outgoing), disabled (routed)
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere # SSH administracion
443/tcp ALLOW IN Anywhere # Servidor HTTPSSi estás conectado a un servidor remoto mediante SSH, asegúrate siempre de añadir la regla que permite el puerto SSH (ufw allow 22/tcp) antes de ejecutar ufw enable, o perderás el acceso a la sesión actual.
Audita los puertos abiertos en tu sistema
No necesitas modificar las reglas de tu sistema para comprobar tu superficie de exposición actual:
- Abre una terminal y ejecuta
ss -tuln(en Linux) olsof -iTCP -sTCP:LISTEN -P -n(en macOS). - Observa la columna
Local Address:Port:- Si un servicio escucha en
127.0.0.1:puertoo[::1]:puerto, solo es accesible desde tu propio equipo. - Si escucha en
0.0.0.0:puertoo*:puerto, está expuesto a otras máquinas de tu red (a menos que un firewall lo bloquee).
- Si un servicio escucha en
- Identifica qué proceso corresponde a cada puerto y verifica si realmente necesitas que esté activo.
§ Autoevaluación
Un servidor tiene una política por defecto `deny incoming` y `allow outgoing`, sin ninguna regla de entrada adicional. Si desde ese servidor ejecutas `curl https://example.com`, ¿por qué recibes la respuesta correctamente?