25 de Mayo de 2010

La seguridad en las conexiones a un servidor de ventanas X nunca ha sido muy bien explicada ni entendida, y como en los sistemas GNU/Linux modernos las cosas simplemente funcionan no hay demasiada motivación para entender este tema. Hasta que las cosas dejan de funcionar; entonces este tema pasa a ser de vital importancia. Y también es importante que los administradores de sistemas conozcan cómo funciona para no dejar abiertos agujeros de seguridad, que podrían ser fatales.

Conexión con el servidor

La conexión de una aplicación cliente a un servidor X se puede realizar a traves de varios protocolos diferentes. En la práctica, en sistemas GNU/Linux, se utilizan solamente dos protocolos: socket local (o socke Unix) y conexión TCP. La aplicación cliente escoge el protocolo, así como la localización del servidor, con la variable de entorno DISPLAY o bien con la opción de línea de comandos -display (o --display, con dos guiones, en aplicaciones modernas).

En el caso de que se vaya a usar un socket local el valor de DISPLAY es un signo de dos puntos seguido del número de display, que suele ser 0, aunque varía en el caso de que se ejecuten varios servidores simultáneamente en la misma máquina. Opcionalmente se puede añadir un punto y el número de pantalla por defecto, útil en el caso de que el servidor X controle varias pantallas. El display más habitual es por tanto :0.0 (o :0). El socket local se crea en /tmp/.X11-unix/Xn, siendo n el número del display.

Si se va a conectar al servidor a través de TCP, entonces el valor de DISPLAY es el nombre o dirección IP del servidor seguido de dos puntos y el número de display. Igual que antes se puede añadir un punto y el número de pantalla por defecto. Por ejemplo para una conexión al servidor local, pero por TCP se usaría un DISPLAY=localhost:0. El puerto TCP utilizado es 6000 más el número de display.

Nótese que las comunicaciones con el servidor X no están cifradas por lo que, si se usa TCP, cualquiera que tenga acceso a la red puede en principio monitorizar las comunicaciones y montar todo tipo de ataques. Es por esto que casi todas las distribuciones modernas de GNU/Linux deshabilitan las conexiones a X por TCP. Puedes comprobar si este es el caso con tu servidor comprobando si el proceso X se ha lanzado con los parámetros -nolisten tcp.

$ ps -efc | grep /X
root 1156 1130 TS tty7 /usr/bin/X :0 -auth /var/run/gdm/auth-for-gdm-JyuKhb/database -nolisten tcp vt7

Si por alguna razón quisieras conectar habilitar las conexiones TCP a tu servidor X, deberías leer la documentación de tu display manager, pues es éste el que lanza el servidor X (gdm con Gnome, kdm con KDE, xdm con otros).

Control de acceso

Cuando una aplicación cliente intenta conectarse a un servidor X, este último comprueba si el anterior está autorizado para acceder al display. Hay tres formas diferentes por las que un cliente puede conseguir permiso de acceso: Acceso universal. Si el servidor se lanza con la opción de línea de comandos -ac, entonces se deshabilita todo el mecanismo de control de acceso. Puede activarse en un servidor en ejecución con el comando xhost + y desactivarse con xhost -. Naturalmente para ejecutar este comando es necesario disponer previamente de permiso de acceso.

Permisos por nombre. El servidor X mantiene una lista de nombres de entidades que tienen permiso de acceso. Estas entidades pueden ser direcciones IP, nombres de host, nombres de ususario o nombres de grupo. Pueden consultarse y manipularse con el comando xhost (véase man xhost para más información). Por ejemplo:

$ xhost +si:localuser:rodrigo #usuario local rodrigo
$ xhost +local: #cualquiera que use el protocolo de acceso local
$ xhost +192.168.1.8 #conexiones desde la IP indicada
$ xhost +si:hostname:saturno #conexiones desde el host "saturno"

Nótese que los nombres de usuario y de grupos solo pueden validarse con conexiones locales, nunca a través de TCP.

Permisos por cookie. Esta es la forma más habitual de autenticación. El display manager genera un número aleatorio (la cookie) y se lo comunica al servidor X en la línea de comandos. Cuando un usuario entra en sesión se escribe ese mismo número en un fichero legible solo por ese ususario. A continuación, cuando una aplicación cliente inicia una conexión con el servidor X envía la cookie para demostrar que pertenece al usuario autorizado. La aplicación cliente sabe dónde esta la cookie gracias a la variable de entorno XAUTHORITY (si esta no está asignada se toma por defecto el fichero $HOME/.Xauthority, si existe). Se puede analizar y manipular el fichero de cookies con el comando xauth.

Ejemplo de configuración

La configuración exacta de tu sistema depende de la distribución GNU/Linux que utilices. Por ejemplo, en mi sistema Ubuntu 10.4, nada más iniciar la sesión tenemos lo siguiente:

$ echo $DISPLAY
:0.0
$ echo $XAUTHORITY
/var/run/gdm/auth-for-rodrigo-HSvcc4/database
$ xauth list
mipc/unix:0  MIT-MAGIC-COOKIE-1  dd9824bad3ec7c4a2c7ccc366d82a563
$ xhost
access control enabled, only authorized clients can connect
SI:localuser:rodrigo
SI:localuser:gdm
SI:localuser:root

La conexión es local, y el fichero con la cookie se guarda en /var/run/gdm en lugar de en $HOME, seguramente por razones relacionadas con el cambio rápido de usuario (varios usuarios con sesiones abiertas al mismo tiempo). Además el usuario local y root tienen acceso al servidor por nombre, con lo que aunque perdiera la cookie seguiría pudiendo conectarme.

sudo

Algunas distribuciones (notablemente las basadas en Debian, como Ubuntu) permiten que las aplicaciones del usuario root lanzadas con sudo tengan acceso al display. Otras distribuciones no lo permiten por defecto. Puedes comprobar cómo se comporta tu Linux con:

$ sudo xlogo

En Debian se consigue este efecto, simplemente preservando el valor de las variables de entorno DISPLAY y XAUTHORITY. Puedes conseguir lo mismo en otros Linux editando la opción env_keep del fichero sudoers (véase man sudoers para más información). Naturalmente, en mi Ubunto 10.4, el usuario root está autorizado por nombre, así que puede conectarse aun sin XAUTHORITY (aunque DISPLAY sigue siendo necesaria, pero esa difícilmente es un secreto).

ssh

La forma preferida para conectarse a un servidor X remotamente es utilizando el comando ssh -X. Esta opción crea un túnel X a través de la conexión segura, de tal manera que las aplicaciones ejecutadas en la máquina remota tienen acceso al servidor X del la máquina local. El mecanismo de funcionamiento de este túnel es el siguiente:

  • El cliente ssh en la máquina local genera una cookie de autenticación y se la envía al servicio ssh remoto, que la añade al fichero $HOME/.Xauthority de la máquina remota. No es necesario crear la variable de entorno XAUTHORITY porque este es el fichero por defecto.
  • El servicio ssh remoto abre el socket TCP 6010 en modo escucha. A continuación asigna la variable de entorno DISPLAY con el valor localhost:10.0. Si ese puerto no está disponible utiliza el 6011 y cambia la variable de entorno por localhost:11.0, y así sucesivamente. El número de pantalla (0 en el ejemplo) en realidad se copia de la pantalla de la variable DISPLAY local.
  • Se crea un túnel entre el socket TCP 6010 remoto y la conexión al servidor X local, sea cual sea el mecanismo local que utilice.
  • Cuando se inicie una aplicación gráfica en la máquina remota, esta leerá la cookie del fichero $HOME/.Xauthority e iniciará una conexión TCP con el puerto local 6010 (o el que corresponda). El cliente ssh local, recibirá la cookie y comprobará que efectivamente es la que generó inicialmente. A continuación crea una conexión con el servidor X local y sustituye la cookie remota por el mecanismo de autenticación que le corresponda localmente.
  • A partir de este punto los datos se transmiten en ambas direcciones a través del túnel sin modificaciones.

1 comment to Control de acceso en el servidor de ventanas X

  1. https://lwn.net/Articles/390016/

Help
:-(icon_sad :-)icon_smile :roll:icon_rolleyes
:-Dicon_biggrin :-Picon_razz :oops:icon_redface
:-xicon_mad :-|icon_neutral :arrow:icon_arrow
8-)icon_cool 8-Oicon_eek :mrgreen:icon_mrgreen
:!:icon_exclaim :?:icon_question :twisted:icon_twisted
;-)icon_wink :evil:icon_evil :idea:icon_idea
:-oicon_surprised :cry:icon_cry
:-?icon_confused :lol:icon_lol

Leave a comment