[Anterior: Tablas] [Contenido] [Siguiente: Traducción de Direcciones de Red]
La acción de filtrar paquetes es bloquear o permitir el paso a los paquetes de datos de forma selectiva, según van llegando a una interfaz de red. Los criterios que usa pf(4) para inspeccionar los paquetes los toma de la información existente en la capa 'Layer 3' (IPv4 y IPv6) y en la capa 'Layer 4' (TCP, UDP, ICMP, y ICMPv6) de las cabeceras de los paquetes. Los criterios que más se utilizan son los de la dirección de origen y de destino, el puerto de origen y de destino, y el protocolo.
Las reglas de filtrado especifican los criterios con los que debe concordar un paquete y la acción a seguir, bien sea bloquearlo o permitir que pase, que se toma cuando se encuentra una concordancia. Las reglas de filtrado se evalúan por orden de secuencia, de la primera a la última. A menos que el paquete concuerde con una regla que contenga la clave quick, se evaluará el paquete comparándolo con todas las reglas de filtrado antes de decidir una acción final. La última regla que concuerde será la «ganadora» y la que dictamine qué acción se tomará con el paquete. Al principio del grupo de reglas de filtrado hay un pass all implícito que indica que si algún paquete no concuerda con ninguna de las reglas de filtrado, la acción a seguir será pass, o sea permitirle el paso.
La sintaxis general, muy simplificada, para las reglas de filtrado es:
action direction [log] [quick] on interfaz [af] [proto protocol] \
from src_addr [port src_port] to dst_addr [port dst_port] \
[tcp_flags] [state]
La práctica recomendada para configurar un cortafuegos es la de tomar una aproximación de «denegación predeterminada»; o sea, denegar el paso a todo y a partir de ahí ir permitiendo el paso a través del cortafuegos de forma selectiva a cierto tráfico. Esta aproximación es la recomendada ya que los posibles fallos se cometerían a favor de la seguridad, y también por que hace más fácil la creación de grupos de reglas.
Para crear una política de filtrado de denegación predeterminada, las primeras dos reglas deben ser:
block in all
block out all
Con esto se bloquea todo el tráfico en todas las interfaces en cualquier dirección, y desde cualquier origen, hasta cualquier destino.
Ahora hay que permitir de forma explícita y selectiva el paso del tráfico a través del cortafuegos, o de lo contrario será bloqueado por la política de denegación predeterminada. Aquí es donde entran en juego los criterios del paquete, como son el puerto de origen/destino, la dirección de origen/destino, y el protocolo. Siempre que se permita el paso de cierto tráfico a través del cortafuegos hay que escribir las reglas de un modo tan restrictivo como sea posible. Esto es para asegurarse de que sólo pasará el tráfico que se permita, y ningún otro.
Algunos ejemplos:
# Permitir el paso al tráfico entrante en la interfaz dc0 de la red local,
# 192.168.0.0/24, hacia la dirección IP 192.168.0.1 de la máquina de OpenBSD.
# También permitir el paso al tráfico saliente que es enviado de vuelta en dc0.
pass in on dc0 from 192.168.0.0/24 to 192.168.0.1
pass out on dc0 from 192.168.0.1 to 192.168.0.0/24
# Permitir el paso al tráfico entrante TCP en la interfaz fxp0 del servidor
# de web que se encuentra en la máquina de OpenBSD. El nombre de la
# interfaz, fxp0, se usa como la dirección de destino para que los paquetes
# sólo concuerden con esta regla si tienen como destino la máquina de OpenBSD.
pass in on fxp0 proto tcp from any to fxp0 port www
Como se ha indicado anteriormente, cada paquete se evalúa con el grupo de reglas de filtrado, desde la primera hasta la última. El resultado predeterminado es el de marcar el paquete para que se le permita el paso; esto puede cambiar con cualquiera de las reglas por las que pasa, y podría cambiar varias veces antes de llegar al final de las reglas de filtrado. La última regla con la que concuerde marcará el resultado. Existe una excepción para esto: la opción quick en una regla de filtrado tiene el efecto de cancelar el procesamiento de cualquier regla consiguiente, y provoca que se ejecute la acción especificada sin más dilación. Veamos un par de ejemplos:
Mal:
block in on fxp0 proto tcp from any to any port ssh
pass in all
En este caso, la línea block puede ser evaluada, pero nunca tendrá ningún efecto, ya que va seguida por una línea que permite el paso de todo.
Mejor:
block in quick on fxp0 proto tcp from any to any port ssh
pass in all
Estas reglas se evalúan de una forma algo diferente. Si un paquete concuerda con la línea block, debido a la naturaleza de la opción quick, se bloqueará el paso a dicho paquete y se ignorará el resto del grupo de reglas.
Una de las funcionalidades importantes de PF es la del «mantenimiento del estado» (keeping state) o «inspección completa del estado» (stateful inspection). La inspección del estado se refiere a la capacidad de PF de llevar un seguimiento del estado, o del progreso, de una conexión de red. Almacenando información sobre cada conexión en una tabla de estado, PF puede determinar rápidamente si un paquete que está pasando a través del cortafuegos pertenece a una conexión ya establecida. Si es así, se le permite pasar a través del cortafuegos sin tener que pasar a través de la evaluación del grupo de reglas.
El mantenimiento del estado tiene muchas ventajas, entre otras que los grupos de reglas son más simples y se obtiene un rendimiento más alto del filtrado de paquetes. PF puede puede hacer que los paquetes que vayan en cualquier dirección concuerden con entradas en la tabla de estado, lo que quiere decir que no es necesario escribir reglas de filtrado que permitan el paso del tráfico de vuelta. Y, como los paquetes que concuerdan con conexiones stateful no pasan a través de la evaluación del grupo de reglas, el tiempo que tarda PF en procesarlos puede reducirse considerablemente.
Cuando una regla tiene la opción keep state, el primer paquete que concuerda con ella crea un estado entre el remitente y el destinatario. A partir de ahí, los paquetes que vayan desde el remitente hacia el destinatario no serán los únicos que concuerden con la entrada de estado y que circunvalen la evaluación de las reglas, sino que también lo harán los paquetes de respuesta desde el destinatario hacia el remitente. Por ejemplo:
pass out on fxp0 proto tcp from any to any keep state
Esta regla permite el paso de cualquier tráfico TCP saliente en la interfaz fxp0, y también permite que el tráfico de respuesta pase de vuelta a través del cortafuegos. El mantenimiento del estado es una funcionalidad muy útil, y su uso mejora de forma significativa el rendimiento del cortafuegos, ya que las búsquedas de estados son mucho más rápidas que la evaluación de un paquete a través de todas las reglas de filtrado.
La opción de «modulación del estado», modulate state, funciona como keep state, con la diferencia que sólo es válida para paquetes TCP. Con modulate state, el ISN de las conexiones salientes es aleatorio. Esta opción es útil para proteger conexiones que hayan sido iniciadas por ciertos sistemas operativos que realizan un pobre trabajo al escoger ISNs. A partir de OpenBSD 3.5, la opción modulate state puede usar usada en aquellas reglas que especifican protocolos diferentes de TCP.
Mantenimiento del estado en paquetes TCP, UDP y ICMP salientes y ISN TCP modulados:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state
Otra ventaja del mantenimiento del estado es que el tráfico ICMP correspondiente pasará a través del cortafuegos. Por ejemplo, si se especifica keep state para una conexión TCP y llega un mensaje ICMP de «requerimiento de ralentización» (source quench ICMP message; es un mensaje de respuesta generado por una pasarela o por el anfitrión de destino, y avisando al anfitrión de origen de la conexión para que ralentice el envío de datos) con referencia a esta conexión TCP, se buscará su concordancia con la entrada apropiada de la tabla de estado y pasará a través del cortafuegos.
El ámbito de un estado es controlado globalmente por la opción de tiempo de ejecución state-policy y por cada regla con las claves de opciones de estado if-bound, group-bound y floating. Estas claves por regla tienen el mismo significado que cuando se usan con la opción state-policy. Ejemplo:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state (if-bound)
Esta regla dictaminaría que para que los paquetes concuerden con el estado deben transitar por la interfaz fxp0.
Nótese que las reglas de nat, binat, y rdr crean un estado implícito para las conexiones que concuerden, siempre que la conexión pase por el filtro del grupo de reglas.
Algunos dicen que «no se puede crear estado con UDP, ya que UDP es un protocolo sin estado». Aunque es cierto que una sesión de comunicación de UDP no tiene ningún concepto de estado (un comienzo y un final de las comunicaciones explícito), esto no tiene ningún impacto en la capacidad de PF para crear estado para una sesión de UDP. En el caso de protocolos sin paquetes de «inicio» ni «final», PF se limita a mantener un seguimiento del tiempo transcurrido desde que ha pasado un paquete que concuerde. Los valores del tiempo agotado (timeout) se pueden configurar en la sección de opciones del fichero pf.conf.
La concordancia de paquetes TCP basada en indicadores es algo que se suele usar para filtrar paquetes TCP que estén intentando abrir una nueva conexión. Aquí se puede ver una lista de indicadores TCP y sus significados:
Para que PF inspeccione los indicadores TCP durante la evaluación de una regla se usa la clave flags con la sintaxis siguiente:
flags check/mask
La parte mask indica a PF que sólo inspeccione los indicadores especificados, y la parte check especifica qué indicadores deben estar activos ("on") en la cabecera para que ocurra una concordancia.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA
Esta regla permite el paso de tráfico TCP con el indicador SYN activo, y sólo mira a los indicadores SYN y ACK. Un paquete con los indicadores SYN y ECE concordaría con la regla anterior, mientras que un paquete con SYN y ACK, o sólo con ACK, no concordaría.
Nota: la siguiente sintaxis tenía soporte en versiones anteriores de OpenBSD:
. . . flags S
Este soporte ya no existe. Ahora hay que especificar siempre una máscara.
Los indicadores se suelen usar junto con reglas keep state para ayudar a controlar la creación de entradas de estado:
pass out on fxp0 proto tcp all flags S/SA keep state
Esto permitiría la creación de estado en cualquier paquete TCP saliente, con el indicador SYN activado entre los indicadores SYN y ACK.
Hay que tener cuidado con el uso de indicadores; hay que entender
qué es lo que se está haciendo y porqué, y tener
cuidado con los consejos recibidos de otros ya que muchos suelen ser
erróneos. Algunas personas han sugerido la creación de
estado «sólo si está activado el indicador SYN, y no
otros». Una regla de este tipo terminaría así
. . . flags S/FSRPAUEW ¡¡mala idea!!
La teoría es crear estado sólo en el inicio de la sesión TCP, y la sesión debería iniciarse con un indicador SYN, y ninguno otro. El problema es que algunos sitios están empezando a usar el indicador ECN, y cualquier sitio que use ECN e intentara conectar con nosotros sería rechazado por una regla de ese tipo. Una directiva mucho mejor es:
. . . flags S/SAFR
Aunque esto es práctico y seguro, también es necesario comprobar los indicadores FIN y RST si se está aplicando la normalización de paquetes (scrub) sobre el tráfico. El proceso de normalización de paquetes hará que PF bloquee cualquier paquete entrante que lleve una combinación ilegal del indicador TCP (como SYN y FIN o SYN y RST). Es muy recomendable que se normalice siempre el tráfico entrante:
scrub in on fxp0
.
.
.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA \
keep state
Normalmente, cuando un cliente inicia una conexión TCP a un servidor, PF pasa los paquetes del saludo inicial (handshake) entre los dos extremos según llegan. Sin embargo, PF también puede hacer de proxy para el saludo inicial. Con el modo proxy, PF completará el saludo inicial con el cliente, iniciará un saludo inicial con el servidor, y pasará los paquetes entre los dos. La ventaja de este proceso es que no se enviará ningún paquete al servidor antes de que el cliente complete el saludo inicial. Esto elimina la amenaza de que desbordamientos TCP SYN falseados puedan afectar al servidor, debido a que una conexión de un cliente falseado no podrá completar el saludo inicial.
La proxy TCP SYN se activa usando la clave synproxy state en las reglas de filtrado. Ejemplo:
pass in on $ext_if proto tcp from any to $web_server port www \
flags S/SA synproxy state
En este ejemplo, PF hará de proxy TCP para las conexiones del servidor de web.
Debido al modo en que funciona synproxy state, también incluye la misma funcionalidad que keep state y modulate state.
La proxy SYN no funcionará si PF está funcionando sobre un bridge(4).
La falsificación de direcciones (spoofing) es cuando un usuario con malas intenciones falsifica la dirección IP de origen en los paquetes que se transmiten, con el objetivo de esconder su dirección real o de suplantar otro nodo en la red. Una vez que el usuario ha falsificado su dirección, puede lanzar un ataque a nivel de red sin revelar la dirección real de origen del ataque, o intentar obtener acceso a servicios de la red que estén restringidos para ciertas direcciones IP.
PF ofrece cierto nivel de protección contra la falsificación de direcciones mediante la clave antispoof:
antispoof [log] [quick] for interface [af]
Ejemplo:
antispoof for fxp0 inet
Cuando se carga un grupo de reglas, cualquier suceso de la clave antispoof se expandirá en dos reglas de filtrado. Asumiendo que la interfaz fxp0 tuviera una dirección IP 10.0.0.1 y una máscara de subred de 255.255.255.0 (o sea, un /24), la regla antispoof anterior se expandiría así:
block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any
Estas reglas realizan dos funciones:
NOTA: Las reglas de filtrado resultantes de la expansión de la regla antispoof también bloquearán los paquetes que se envíen por la interfaz de loopback hacia direcciones locales. Es necesario permitir el paso de estas direcciones de forma explícita. Por ejemplo:
pass quick on lo0 all
antispoof for fxp0 inet
El uso de antispoof se debe restringir a las interfaces a las que se les haya asignado una dirección IP. El uso de antispoof en una interfaz sin una dirección IP resultará en reglas de filtrado como:
block drop in on ! fxp0 inet all
block drop in inet all
Con estas reglas existe el riesgo de bloquear todo el tráfico entrante en todas las interfaces.
La identificación pasiva del sistema operativo (OSFP por sus siglas en inglés) es un método para detectar pasivamente el sistema operativo de un host remoto basado en ciertas características contenidas en sus paquetes SYN TCP. Esta información puede usarse después como criterio en las reglas de filtrado.
PF determina el sistema operativo remoto comparando las características de un paquete SYN TCP con el archivo de fingerprints, que por omisión es /etc/pf.os. Una vez que PF está habilitado, la lista actual de fingerprints puede verse con la siguiente instrucción:
# pfctl -s osfp
Dentro de una regla de filtro, un fingerprint puede especificarse mediante una clase de sistema operativo, versión o nivel de subtipo/parche. Cada uno de estos elementos se lista en la salida de la instrucción pfctl de arriba. Para especificar un fingerprint en una regla de filtrado se usa la palabra clave os:
pass in on $ext_if any os OpenBSD keep state
block in on $ext_if any os "Windows 2000"
block in on $ext_if any os "Linux 2.4 ts"
block in on $ext_if any os unknown
La clase especial de sistema operativo unknown hace que los paquetes concuerden con la regla si el fingerprint del sistema operativo es desconocido.
TOME NOTA de lo siguiente:
Por definición, PF bloquea los paquetes con las opciones IP activadas. Esto puede hacer las cosas más difíciles para utilidades de detección de sistemas operativos (OS fingerprinting) como nmap. Si se tiene una aplicación que requiere el paso de estos paquetes, como multidifusión o IGMP, se puede usar la directiva allow-opts:
pass in quick on fxp0 all allow-opts
A continuación tenemos un ejemplo de un grupo de reglas de
filtrado. La máquina en la que está funcionando PF
actúa como cortafuegos entre una red interna pequeña e
Internet. Sólo se muestran las reglas de filtrado; las reglas
de queueing,
nat,
rdr,
etc.. se han omitido en este ejemplo.
ext_if = "fxp0"
int_if = "dc0"
lan_net = "192.168.0.0/24"
# tabla que contiene todas las direcciiones IP asignadas al firewall
table <firewall> const { self }
# normalizar los paquetes entrantes
scrub in all
# configurar una política de denegación predeterminada
block in all
block out all
# permitir el paso del tráfico en la interfaz de loopback
# en cualquier dirección
pass quick on lo0 all
# activar la protección contra la falsificación de direcciones
# para la interfaz interna
antispoof quick for $int_if inet
# permitir sólo conexiones por ssh si provienen
# desde la máquina de confianza, 192.168.0.15;
# usar "block return" para que se envíe un TCP RST
# para cerrar inmediatamente las conexiones bloqueadas;
# usar "quick" para que las reglas "pass" que
# vienen a continuación no anulen esta regla.
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
to $int_if port ssh flags S/SA
# permitir el paso del tráfico hacia y desde la red local
pass in on $int_if from $lan_net to any
pass out on $int_if from any to $lan_net
# permitir el paso de paquetes tcp, udp y icmp
# salientes en la interfaz externa (Internet);
# mantener el estado en udp y icmp, y modular
# el estado en tcp.
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
# permitir el paso de las conexiones entrantes de ssh
# en la interfaz externa siempre que su destino NO sea
# el cortafuegos (o sea, aquéllas cuyo destino sea
# una máquina en la red local); registrar el paquete inicial
# para que podamos ver más tarde quién intenta conectar.
# Usar el proxy tcp syn para la conexión.
pass in log on $ext_if proto tcp from any to ! <firewall> \
port ssh flags S/SA synproxy state
|
[Anterior: Tablas] [Contenido] [Siguiente: Traducción de Direcciones de Red]