Conexión remota segura SSH

SSH (Secure SHell) es un protocolo similar a Telnet que permite abrir un shell en una máquina remota, con la diferencia de que SSH encripta toda la información que viaja por la red utilizando criptografía híbrida. Este procolo se implementa con arquitectura cliente-servidor, por lo que necesita:

  • un servidor SSH en la máquina remota (por defecto, en el puerto 22 TCP).
  • un cliente SSH que nos permita conectarnos al servidor.

En Linux se utiliza la implementación SSH de OpenBSD, denominada OpenSSH (openssh.com/es/, paquetes openssh-server openssh-client), que proporciona varias aplicaciones:

  • el servidor SSH (sshd, archivo de configuración /etc/ssh/sshd_config) y el cliente SSH (ssh, archivo de configuración /etc/ssh/ssh_config), que permiten obtener un shell remoto, ejecutar un comando remoto y entunelar protocolos.
  • el comando scp (secure copy), que permite la copia remota segura de archivos.
  • el servidor y el cliente SFTP (Secure FTP) (sftp-server y sftp).

Obtener un shell remoto con SSH

Veamos detallamente cómo funciona una conexión SSH:

  1. el servidor arranca con el script de inicio /etc/init.d/ssh.
  2. el cliente inicia la conexión:
    $ ssh usuario@servidor

    Podemos utilizar la IP o el nombre del servidor. Si no especificamos el usuario, utilizará el usuario que está realizando la conexión. Por ejemplo, si el usuario francis desde la máquina asterix quiere conectarse a obelix como mario, ejecutará:

    francis@asterix:~$ ssh mario@obelix
  3. el servidor comprueba si el host del cliente tiene permiso para conectar, tras lo cual cliente y servidor intercambian en texto plano sus identificadores de versión, para comprobar si los protocolos soportados coinciden y la comunicación es posible.
  4. el servidor envía al cliente su clave pública DSA (algoritmo asimétrico) en texto sin cifrar, que el cliente usará para cifrar los mensajes hacia el servidor, haciéndolos sólo legibles para el propio servidor.
  5. si no es la primera vez que se conecta a ese servidor, el cliente compara la clave pública recibida del servidor con la que tiene almacenada para verificar su autenticidad. Si es la primera vez que se conecta a ese servidor y no la tiene almacenada, el cliente no sabe si la clave pública recibida es realmente la del servidor o la de un impostor que ha interceptado la conexión, lo que se conoce con el nombre de ataque man in the middle, por lo que pide confirmación al usuario para aceptarla como válida:
    The authenticity of host obelix (192.168.1.3) can't be established.
    DSA key fingerprint is e9:df:72:2c:eb:1d:bf:b2:3a:38:96:2a:3b:6b
    Are you sure you want to continue connecting (yes/no)?

    Para confirmarlo el usuario debería obtener el fingerprint por otro medio alternativo y seguro: correo electrónico cifrado, por teléfono, correo postal, en persona, etc. Confirmar la clave sin verificarla adecuadamente implica asumir el riesgo de una posible suplantación. Si confiamos en la clave, le decimos al cliente que continúe con la conexión:

    yes
    Warning: Permanently added obelix (DSA) to the list of known hosts.

    Como hemos confiado en la clave pública recibida, el cliente nos informa de que ésta se ha añadido al archivo ~/.ssh/known_hosts, donde se almacenan los hosts conocidos. En adelante cada vez que el cliente se conecte a ese servidor comparará la clave pública recibida al iniciar sesión con la almacenada:

    • si son iguales, continuará con el proceso de conexión.
    • si son diferentes, nos avisará y pedirá confirmación para el nuevo fingerprint:
      key_read failed
      The authenticity of host obelix (192.168.1.3) can't be established.
      DSA key fingerprint is e9:df:72:2c:eb:1d:bf:b2:3a:38:96:2a:3b:6b
      Are you sure you want to continue connecting (yes/no)?
  6. el cliente genera una clave de sesión (válida sólo para la sesión en curso), selecciona un algoritmo de cifrado simétrico y envía un mensaje conteniendo la clave de sesión y el algoritmo simétrico seleccionado, cifrado con la clave pública DSA del servidor. A partir de este momento todo el tráfico entre cliente y servidor viaja cifrado utilizando el algoritmo de cifrado simétrico seleccionado y la clave de sesión.
  7. ahora el cliente se debe identificar ante el servidor, cosa que haremos mediante contraseña (también puede hacerse mediante claves DSA, sin necesidad de password). El servidor solicita al usuario la contraseña correspondiente a usuario:
    mario@obelix's password:

    Si el login es válido y no hay restricciones adicionales obtendremos un shell en el servidor SSH, de modo que podremos usar el sistema como si estuviéramos sentados allí, con los privilegios que tenga ese usuario:

    mario@obelix:~$

    Identificación del cliente mediante clave pública

    El cliente puede identificarse mediante clave pública, sin password. Para ello:

    - creamos en el cliente una clave RSA:

    francis@asterix:~$ ssh-keygen -t rsa -f ~/.ssh/id_rsa

    - activamos ssh-agent en el cliente para que no nos pida la pass-phrase:

    francis@asterix:~$ eval `ssh-agent -s`
    Agent pid 12297
    francis@asterix:~$ ssh-add
    Enter passphrase for /home/francis/.ssh/id_rsa:
    Identity added: /home/francis/.ssh/id_rsa (/home/francis/.ssh/id_rsa)

    - copiamos en el servidor la clave pública (~/.ssh/id_rsa.pub):

    francis@asterix:~$ scp ~/.ssh/id_rsa.pub mario@obelix:~/.ssh/id_rsa.pub

    - la añadimos en el servidor al final del fichero ~/.ssh/authorized_keys:

    mario@obelix:~$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

    - y comprobamos que podemos iniciar una sesión SSH sin password ni pass-phrase:

    francis@asterix:~$ ssh mario@obelix
    mario@obelix:~$
  8. para salir de la sesión SSH teclearemos exit, retornando al shell de la máquina cliente:
    mario@obelix:~$ exit
    logout
    Connection to obelix closed
    francis@asterix:~$

Ejecutar un comando remoto con SSH

En vez de obtener un shell en la máquina remota, podemos simplemente ejecutar un comando en ella. Para ello, usaremos el cliente SSH con la siguiente sintaxis:

$ ssh usuario@servidor "comando"

Usaremos comillas dobles para evitar que el cliente interprete el comando. Una vez introducido el password se ejecutará el comando, retornando directamente al shell de la máquina cliente. Por ejemplo:

francis@asterix:~$ ssh mario@obelix "cat /etc/hostname"
mario@obelix's password:
obelix
francis@asterix:~$

Copiar un archivo con scp

El comando scp (secure copy) nos permite intercambiar ficheros o directorios (tanto enviar como recibir) entre el cliente y el servidor utilizando SSH. Para copiar recursivamente un directorio usaremos la opción -r. La sintaxis es:

$ scp origen destino
  • Para subir archivos o directorios del cliente al servidor la sintaxis sería:
    $ scp archivo_local usuario@servidor:directorio_remoto

    Por ejemplo:

    francis@asterix:~$ scp file1 mario@obelix:/home/mario/
  • Para bajar archivos o directorios desde el servidor al cliente la sintaxis sería:
    $ scp usuario@servidor:archivo_remoto directorio_local

    Por ejemplo:

    francis@asterix:~$ scp mario@obelix:/home/mario/file2 ./

En ambos casos nos pedirá el password. Introducimos la contraseña y se copiará el archivo, retornando directamente al shell de la máquina cliente:

Password:
file1      100%     2837 KB     702.7 KB/s      00:06
mario@pc266:~$

Servidor SFTP (Secure FTP)

OpenSSH incluye un servidor SFTP que permite enviar y recibir ficheros utilizando SSH: es un servidor FTP encriptado. Cuando un cliente SFTP se conecta al servidor SSH bajo el esquema sftp://, el servidor SSH lanza el proceso hijo sftp-server, que pide el password y establece la conexión.

OpenSSH incluye también un cliente SFTP interactivo de línea de comandos, sftp, que utiliza los mismos comandos que ftp (cd, lcd, get, put, mkdir…) y cuya sintaxis es:

$ sftp usuario@servidor
sftp>

Pero es mucho más cómodo conectar desde un cliente SFTP gráfico como Konqueror:

SFTP

Entunelar protocolos con OpenSSH (Port Forwarding)

Con OpenSSH se puede crear un túnel encriptado entre dos máquinas y enviar a través de él los datos de otros protocolos (es un tipo de VPN, Virtual Private Network, Red Privada Virtual). Esto es útil, por ejemplo:

  • para entunelar protocolos que son inseguros por enviar la información sin cifrar, como Telnet, FTP, HTTP, MySQL, las X, etc.
  • para atravesar un firewall donde sólo está permitido SSH.

El único requisito para configurar un túnel SSH es que sea un protocolo basado en TCP, por lo que este método no se puede aplicar a servicios UDP como DHCP, NFS, NetBIOS, etc.

Vamos a verlo con un ejemplo. Desde el cliente queremos hacer consultas al servidor de base de datos MySQL instalado en el servidor. Pero MySQL no soporta conexiones seguras entre los clientes y el servidor, de manera que la identificación de los usuarios remotos y los datos de las consultas serán visibles a cualquier máquina de la red. Por ello, utilizaremos SSH para establecer una conexión segura, de la siguiente manera:

Entunelar MySQL

  • en el cliente, el cliente MySQL (mysql) hace una petición al puerto 3306 TCP de localhost, donde escucha el cliente SSH (ssh).
  • el cliente SSH (ssh) escucha el puerto 3306 TCP y redirecciona las peticiones al servidor SSH (sshd) a través del túnel, de manera que todo el tráfico de datos entre el cliente y el servidor MySQL van cifrados por la red.
  • en el servidor, el servidor SSH (sshd) redirecciona el tráfico procedente del túnel al puerto 5000 TCP de localhost, donde escucha el servidor MySQL (mysqld), de manera que éste ve las conexiones como procedentes de la propia máquina.

Veamos cuál es el procedimiento a seguir:

  1. configuramos el servidor MySQL para que escuche en el puerto 5000 TCP de localhost. Para ello, editaremos el archivo de configuración /etc/mysql/my.cnf:
    [mysqld]
    #skip-networking
    bind-address = 127.0.0.1
    port = 5000

    Una vez reiniciado el servidor MySQL, sólo podremos conectar con la base de datos desde localhost, en la máquina local.

  2. levantamos el túnel desde el cliente con el siguiente comando (el túnel se establecerá una vez introducido el password):
    francis@asterix:~$ ssh -N -L 3306:127.0.0.1:5000 usuario@servidor
    Password:
    • 3306:127.0.0.1:5000: abre un túnel que conecta el puerto 3306 del cliente con el 5000 del servidor, en cuyos extremos están el cliente y el servidor SSH.
    • -N: esta opción establece el túnel, ya que indica no ejecutar comandos remotos.
    • -L: indica que este extremo es el cliente del túnel.
  3. para conectarnos al servidor MySQL desde el cliente tenemos que conectar con el extremo local del túnel, ejecutando:
    francis@asterix:~$ mysql -u root -h 127.0.0.1 -p test
    Enter password:
    mysql>

Conectar con un servidor SSH Linux desde Windows

El cliente SSH Putty (chiark.greenend.org.uk/~sgtatham/putty/) nos permitirá conectar con un servidor SSH Linux desde Windows.

putty

Artículos en la categoría "Encriptación y Criptografía"

  1. Checksum MD5
  2. Conexión remota segura SSH
  3. Software de encriptación GPG
  4. APT seguro (Secure APT)
  5. HTTPS (HTTP seguro): SSL

12 Comments:

  1. Me parece un buen post que explica muy bien el funcionamiento de ssh, me ha ayudado mucho.

  2. Mira no se nada de linux, estoy comenzando en este mundo, pero de verdad, tremenda explicacion la que hacen ustedes, los felicito.

  3. hola amigos ahi les dejo un programita en perl para hacer un acceso remoto, respaldar una bd y traerla de regreso. espero les sirva de algo.

    se definen 2 variables para las 2 db que tengo pero en lo que puse solo respalda una para la otra se hace exactamente lo mismo.

    #!/usr/bin/perl

    # Definimos los modulos de perl que vamos a usar
    use Net::SSH::Perl;
    use Net::SCP::Expect;

    # Host del servidor que contiene las BD
    $host=”148.211.200.6″;

    #Nombre que le pondremos al respaldo sql
    $archivo=”CW-Horde.sql”;
    $archivo1=”CW-mysql.sql”;

    # Ruta donde se dejaran los archivos respaldados
    $ruta=”/RESPALDO/BASESDEDATOS/CorreoWeb/”;

    #Usuario SSH
    $userS=”root”;
    $passwordS=”**********”;

    #Credenciales de Base de Datos
    $user=”respaldo”;
    $password=”********”;

    # Se hace la conexion ssh al servidor a respaldar
    $ssh=Net::SSH::Perl->new($host) or die $!;
    $ssh->login($userS, $passwordS);

    # Se Respalda la BD horde
    ($stdout, $stderr, $exit)=$ssh->cmd(“mysqldump -u $user –password=$password horde > $archivo”);
    die $! unless (!$exit);

    # Creamos la conexion para transferir el archivo – respaldo de BD
    $scpe=Net::SCP::Expect->new(host => $host, user => $userS, password => $passwordS) or die $!;

    # Transferimos el archivo para horde
    #$ssh->cmd(“tar -cf $archivo.tar $archivo”);
    $scpe->scp(“$host:$archivo”, “$ruta/$archivo”);
    $ssh->cmd(“rm $archivo”);

    #mandamos llamar a un sh.
    #esto lo hago para mandarle estos parametros a un shell y en el sh le pongo al nombre y la fecha ya dentro de mi #servidor de respaldos
    system(`/opt/mueve-nombre.sh $archivo $ruta`);

  4. Muy útil tu información.

    Gracias

  5. necesito urgente un software free que me encripte la informacion que se envia por la red inalambrica desde un servidos Centos hacia pc clientes que tienen winxp, en el cual se va a manejar un sistema hecho en PHP con una base hecha en mysql

  6. la verdad es el primer articulo al q le entiendo la explicacion es detalladisima y me va a ayudar un monton con mi deber si pueden ayudarm seria un exito ya q recien estoy empezando y necesito una buena nota…

  7. Se pasaron.
    Sin ser un experto, debo admitir que llevo algo de linux en el cuerpo, por lo que siempre leo manuales de todas las paginas que existen de linux, que no son pocas, pero son realmente minoría los tutoriales con esta calidad, hechos para personas que no saben nada o que saben mucho.
    Se agradece

  8. Muy interesante el articulo, me ayudo mucho entender como funciona el SSH. Como puedo implementar para acceder a una base de datos SQL Server 2005 que esta detrás de un servidor linux que es mi servidor de Internet. El SQL Server 2005 esta en Windows 2003 y esta en la red local y tiene salida a Internet a través del servidor linux.
    Seria algo parecido al ejemplo “Entunelar protocolos con OpenSSH (Port Forwarding)” solo que la base de datos esta en otra maquina (Windows).
    Agradezco de ante manos cualquier ayuda que puedan darme.
    Saludos.

  9. RICARDO DAMIAN LUCISICH

    Todo Ok, pero mi pregunta es la siguiente. He instalado Ubuntu 10.04 intentado dejar window$, pero encuentro el inconveniente que tengo una aplicación que funciona como cliente servidor en window$ y no lo puedo hacer correr en Ubuntu. Bajé wine, andan todos los programas y aplicaciones pero cuando quiero inicializar el archivo ejecutable del servidor me sale el mensaje error no socket. Bajé todas las librerías con winetricks y nada. El mismo programa en versiones anteriores que no era en arquitectura servidor cliente corre bien en wine. El problema es la configuración para que inicialice el servidor. Soy nuevo en Linux y a la fecha creo que el tema está en convigurar el cliente servidor y hacer correr la aplicación. Pues bien, si alguien puede ayudarme aquí volveré por la respuesta. P.D. La aplicación es un sistema de gestión lex doctor http://www.lex-doctor.com pueden bajar una demo es el archivo instalar.exe que si lo ejecutan bajo wine se instala perfectamente en linux, creando dos iconos uno llamado “lex servidor” y otro llamado “lex cliente” pero el tema es hacer levantar el servidor , ahí es donde sale el mensaje de error. Espero ayuda. Saludos

  10. Gracias se me habia olvidado la sentencia para conectarse (ssh usuario@server). Hacia tiempo que no usaba linux (ya lo extrañaba).

  11. Buenas, estoy transfiriendo un archivo txt mediante SSH, pero cuando lo consulto en el servidor destino SSH, el primer registro se visualiza distorcionado con 3 caracteres especiales. Cuando consulto la copia que dejo en el cliente SSH todos los registros se visualizan de forma correcta en el txt. Parece que se está distoricionando en el proceso de encriptación.. Alguien me puede ayudar.