SSH

Tradicionalmente el intercambio de datos entre sistemas Unix (desde la transferencia de ficheros o la compartición de archivos vía NFS hasta el acceso remoto) se ha realizado utilizando mecanismos en los que la seguridad era un factor poco importante frente a otros como la velocidad o la disponibilidad. Sin embargo, conforme ha ido aumentando la calidad de los medios de transmisión (en la actualidad cualquier pequeña organización tiene al menos una red Fast Ethernet capaz de alcanzar velocidades de 100 Mbps, cuando no una ATM, una FDDI o incluso una GigaEthernet que alcanza los 1000 Mbps de velocidad), y también conforme ha ido aumentando la peligrosidad de las redes, especialmente de Internet, se ha ido considerando más el grave problema que implica una transmisión de datos en texto claro, ya sea un telnet, un ftp o incluso la transmisión de datos que tiene lugar al utilizar sistemas de ficheros en red. Por suerte, en la actualidad, casi nadie sigue usando los medios clásicos de intercambio de datos entre equipos Unix: por ejemplo, muy poca gente sigue conectando mediante telnet a máquinas remotas, mientras que hace unos pocos años era habitual ver estas conexiones incluso entre máquinas separadas por multitud de redes. Casi todos los mecanismos clásicos se han reemplazado por protocolos que incorporan el cifrado en mayor o menor medida, de forma que un pirata que captura datos transmitidos entre sistemas lo tiene muy difícil para conseguir información importante, como una clave de usuario; ejemplos de protocolos que incorporan la criptografía son SSL (Secure Socket Layer) o TCFS (Transparent Cryptographic File System, del que ya hemos hablado en este proyecto).

Dentro de todo estos modelos considerados seguros está Secure Shell (SSH), un software cuya principal función es permitir la conexión remota segura a sistemas a través de canales inseguros, aunque también se utiliza para la ejecución de órdenes en ese sistema remoto o transferir ficheros desde o hacia él de manera fiable ([Ylo96]); es, por tanto, el sustituto ideal de órdenes como telnet, ftp o r$\ast $ de Unix BSD. Todo esto utilizando RSA, SecurID, Kerberos, TIS o la autenticación clásica de Unix (login y password). Además, y entre otras características, SSH también soporta el cifrado automático en sesiones X-Window o modelos de seguridad más avanzados, como el cifrado en NFS o la construcción de redes privadas virtuales; su código fuente es libre para uso no comercial (existe otro software casi completamente compatible con ssh y completamente libre, denominado OpenSSH) y se puede obtener en http://www.ssh.fi/. En la actualidad, SSH funciona sobre la mayoría de clones de Unix (también existen versiones para Windows y MacOS), y es ampliamente utilizado en todo tipo de entornos, desde universidades a bancos pasando por empresas de cualquier sector.

SSH está formado por un programa servidor, sshd, varios programas cliente (ssh y scp principalmente) y pequeñas aplicaciones para su configuración, como ssh-add, ssh-keygen o ssh-agent. El programa demonio (sshd) se ejecuta en la máquina contra la cual conectamos, mientras que los clientes se han de ejecutar evidentemente en el sistema desde el cual conectamos; así, podemos iniciar una sesión en la máquina remota con una orden como la siguiente:
anita:~# ssh -l toni rosita
toni's password: 
Last login: Thu Apr  6 03:58:32 2000 from anita
Linux 2.2.6
"A witty saying proves nothing."
                -- Voltaire

rosita:~$
El parámetro `-l' nos permite indicar el nombre de usuario en el sistema remoto (en caso contrario, se utilizará el mismo nombre que se posee en la máquina local); SSH también permite especificar desde línea de comandos una orden a ejecutar en la máquina a la que conectamos, de forma que cuando esta orden finalice se cerrará la conexión entre ambos sistemas:
anita:~# ssh -l toni luisa w
toni's password:
  3:15am  up 5 days,  1:30,  5 users,  load average: 1.12, 1.04, 1.01
USER     TTY      FROM     LOGIN@   IDLE   JCPU   PCPU  WHAT
root     tty1     -        Sat12am  5days  0.02s  0.02s  bash           
toni     ttyp1    :0.0     Sun 3pm  1:02   0.18s  0.13s  telnet rosita 
toni     ttyp2    :0.0     Sun 4am  2.00s  2.40s  2.04s  vi tools.tex 
toni     ttyp4    anita    Tue 1am  0.00s  1.31s  0.02s  w 
anita:~#
Como hemos podido ver, ssh se utiliza básicamente para iniciar sesiones o ejecutar comandos en un sistema remoto; el otro programa cliente, scp, es utilizado para transferir ficheros entre máquinas, de una forma similar a rcp, lo que por ejemplo permite sustituir el ftp tradicional por este mecanismo. Si por ejemplo deseamos copiar todos los ficheros del directorio /export/home/toni/ conectando al sistema remoto bajo el nombre de usuario toni en el directorio /tmp/ de la máquina local, lo podemos conseguir con una orden como esta:
luisa:~# scp -r toni@anita:/export/home/toni/ /tmp/
toni's password:
luisa:~#
Como podemos ver, estamos indicando el nombre de usuario y el del sistema remotos separados por `@', y separados a su vez de la ruta origen por el signo `:'.

Pero, >qué es lo que realmente hace cualquiera de estos clientes contra el servidor sshd? Si no indicamos lo contrario con la opción `-p', el cliente conecta al puerto 22 de la máquina servidora y verifica que esta máquina es realmente con la que queremos conectar, intercambia las claves de cifrado entre sistemas (cifradas a su vez, para evitar que un atacante pueda obtener la información) y autentica utilizando .rhosts y /etc/hosts.equiv (como los protocolos r-$\ast $), RSA o claves de usuario; si todo es correcto, el servidor asigna una terminal virtual (generalmente) a la conexión y lanza un shell interactivo. Podemos ver con detalle este proceso utilizando la opción `-v' del cliente:
luisa:~# ssh -v -l toni luisa
SSH Version 1.2.21 [i486-unknown-linux], protocol version 1.5.
Standard version.  Does not use RSAREF.
luisa: Reading configuration data /etc/ssh_config
luisa: ssh_connect: getuid 0 geteuid 0 anon 0
luisa: Connecting to luisa [192.168.0.2] port 22.
luisa: Allocated local port 1023.
luisa: Connection established.
luisa: Remote protocol version 1.5, remote software version 1.2.21
luisa: Waiting for server public key.
luisa: Received server public key (768 bits) and host key (1024 bits).
luisa: Host 'luisa' is known and matches the host key.
luisa: Initializing random; seed file /root/.ssh/random_seed
luisa: Encryption type: idea
luisa: Sent encrypted session key.
luisa: Received encrypted confirmation.
luisa: Trying rhosts or /etc/hosts.equiv with RSA host authentication.
luisa: Remote: Rhosts/hosts.equiv authentication refused:\
       client user 'root', server user 'toni', client host 'luisa'.
luisa: Server refused our rhosts authentication or host key.
luisa: No agent.
luisa: Doing password authentication.
toni's password:
luisa: Requesting pty.
luisa: Failed to get local xauth data.
luisa: Requesting X11 forwarding with authentication spoofing.
luisa: Requesting shell.
luisa: Entering interactive session.
Last login: Thu Apr  6 04:13:41 2000 from luisa
Linux 2.2.6
If you want divine justice, die.
                -- Nick Seldon

luisa:~$ exit
logout
Connection to luisa closed.
luisa: Transferred: stdin 5, stdout 491, stderr 29 bytes in 2.6 seconds
luisa: Bytes per second: stdin 1.9, stdout 189.0, stderr 11.2
luisa: Exit status 0
luisa:~#
Como sucede en cualquier programa cliente-servidor, la configuración de la parte cliente es mucho más sencilla que la de la parte servidora: ni siquiera es necesario el fichero de configuración general /etc/ssh_config, donde se definen parámetros por defecto (que cada usuario puede modificar para sí mismo en sus propios ficheros o en línea de órdenes). Sólamente necesitamos el ejecutable (por ejemplo, ssh), que generará en el directorio $HOME/.ssh de quien lo ejecute varios ficheros necesarios para su funcionamiento; quizás el más importante sea known_hosts, donde se almacenan las claves públicas de los diferentes sistemas a los que se conecta. Estas claves, una por línea, se guardan la primera vez que se conecta a una determinada máquina, algo que el cliente indica con un mensaje de esta forma:
rosita:~# ssh -l toni luisa
Host key not found from the list of known hosts.
Are you sure you want to continue connecting (yes/no)? yes
Host 'luisa' added to the list of known hosts.
toni's password: 
Last login: Thu Apr  6 23:20:42 2000 from :0.0
Linux 2.2.6
Drive defensively.  Buy a tank.

luisa:~$
Por su parte, la configuración del servidor es algo más compleja; en el archivo /etc/sshd_config, fichero de configuración del demonio sshd, se especifican todos los parámetros necesarios para su funcionamiento. Algunos de estos parámetros, quizás los más útiles, son AllowHosts y DenyHosts, donde como su nombre indica se referencian los sistemas desde los que la conexión a nuestro demonio se permite o se deniega; al contrario de lo que mucha gente sigue pensando, utilizar SSH no implica tener disponible el servicio para todo el mundo, y es aquí donde indicamos los sistemas desde donde permitimos conexiones. Además, podemos servir sshd desde inetd modificando convenientemente /etc/inetd.conf en lugar de hacerlo como demonio independiente, de forma que podemos aprovechar un software como TCP Wrappers para restringir conexiones; el único inconveniente de este modelo es que cada vez que alguien conecta al demonio éste tiene que generar una clave RSA para esa conexión, lo que en determinadas situaciones puede sobrecargar demasiado al sistema. Si de cualquier forma queremos seguir este mecanismo, hemos de modificar /etc/services para añadir una línea como la siguiente:
ssh             22/tcp
Y también modificaremos /etc/inetd.conf añadiendo la configuración del nuevo servicio:
ssh  stream  tcp     nowait  root    /usr/sbin/tcpd /usr/local/sbin/sshd -i
Tras lo cual, como cada vez que modificamos este archivo, hemos de conseguir que inetd lo relea enviándole al demonio la señal SIGHUP.
© 2002 Antonio Villalón Huerta