.. _vsftpd: |FTP| clásico ************* .. warning:: Se recomienda encarecidamente implementar otra solución de transferencia de ficheros como :ref:`sftp `. Para montar un clásico |FTP| utilizaremos `el servidor vsftpd `_, que se jacta de ser el servidor |FTP| más seguro. Es, ciertamente, un servidor simple que procura mantener un número limitado de características en aras a lograr seguridad y rapidez. Instalación =========== Es sencilla al encontrarse en los repositorios de *debian*:: # apt-get install vsftpd Su configuración se encuentra dentro del directorio :file:`/etc/vsftpd.conf` y, por defecto, permite el acceso de los usuarios definidos en el sistema (los validables haciendo uso de la autenticación con |PAM|) excepto los incluidos en el fichero :file:`/etc/ftpusers`, ya veremos por qué. Configuración ============= Básicamente consiste en modificar el valor de las directivas existentes, descomentar otras y añadir algunas que no aparecen, según nuestras necesidades. Intentaremos agrupar la explicación de algunas según el proposito que busquemos. Escucha ------- :program:`vsftpd` soporta tanto ser requerido por un `superservidor tipo inetd `_ como estar a la escucha constantemente (lo que se conoce como :dfn:`standalone`). A este efecto tiene dos directivas ``listen`` y ``listen_ipv6``: =============== ================= =============================================== ``listen`` ``listen_ipv6`` Descripción del efecto =============== ================= =============================================== NO NO Arrancado con :program:`xinetd` o similar\ [#]_ YES NO Acepta sólo tráfico IPv4. NO YES Acepta tráfico IPv4 y tráfico IPv6. YES YES Error. No es posible la combinación. =============== ================= =============================================== Por otra parte, hay ciertas directivas relacionadas con los puertos que se usarán para la conexión: :kbd:`listen_port` para definir qué puerto de escucha usa el canal de control, si es que se quiere usar un puerto distinto al **21**. :kbd:`connect_from_port_20` que define desde qué puerto abre el servidor el canal de datos, si se utiliza :ref:`el modo activo `. Su valor predeterminado es **NO**, lo cual quiere decir que :program:`vsftpd` abrirá la conexión usando un puerto al azar, en vez del **20**. Que el servidor prefiera usar un puerto distinto al visto en la teoría se debe a que el **20** es un puerto privilegiado y, por tanto, sólo puede iniciar conexión el administrador. Eso obliga a ejecutar el servidor como administrador lo cual es un riesgo de seguridad. En principio, los clientes deberían admitir que el puerto de datos no fuera el **20**, así que no deberíamos tocar esta configuración. :kbd:`ftp_data_port` Si la directiva anterior se definió como **YES**, define cuál es el puerto para abrir el canal de datos en *modo activo*. Por defecto, claro está, su valor es **20**. :kbd:`pasv_min_port`/:kbd:`pasv_max_port` Son dos directivas que permiten definir un límite inferior y un límite superior para el puerto que se indicará al cliente que utilice al abrir el canal de datos en el *modo pasivo*. Esto podría ayudar a la configuración del cortafuegos. .. seealso:: En uno de los epígrafe dedicado a la configuración del cortafuegos hay una sección dedicada a la :ref:`configuración del cortafuegos con servidores FTP `. Esta configuración evita usar estas dos directivas, pero a costa de obligar al cortafuegos a hacer un seguimiento de las conexiones |FTP|. .. _ftp-anonimo: Acceso anónimo -------------- Los servidores, tradicionalmente, han permitido el acceso anónimo al servidor, esto es, la posibilidad de identificarse en el sistema sin tener asignado un usuario. Generalmente, exigen que se indique como usuario *anonymous* y como contraseña cualquier cadena, aunque en origen se indicaba el correo electrónico del usuario. Para habilitar el acceso anónimo es necesario hacer:: anonymous_enable=YES que configura un acceso con estas características: * El usuario anónimo se corresponde con el usuario local *ftp*. * Sólo se tiene permisos de lectura (o sea, sólo puede ver los ficheros disponibles y descargar aquellos que le interesen). * Se accede al directorio :file:`/srv/ftp` y se está enjaulado en él, es decir, es imposible salir de él. Para modificar este comportamiento predeterminado hay otras directivas:: anon_root=/otro/directorio/distinto que permite modificar el directorio de enjaulado del usuario anónimo. .. warning:: El usuario, en este caso *ftp*, no puede tener permisos de escritura sobre el directorio en el que se enjaula. :: anon_upload_enable=YES permite subir ficheros. Se requiere también, no obstante, habilitada la directiva ``write_enable``. Véase más adelante el permiso de escritura para :ref:`usuarios locales `. :: anon_mkdir_write_enable=YES anon_other_write_enable=YES estas directivas permiten respectivamente la creación de nuevos subdirectorios y otros permisos de escritura (como borrado o renombrado). .. note:: Hay aún otra directiva que cobra bastante importancia cuando el usuario anónimo sube ficheros al servidor:: anon_world_readable_only=YES Al estar activa por defecto, obliga a que el fichero sólo pueda descargarse si es universalmente accesible (o sea, todos los usuarios tengan permiso de lectura). Cobra importancia, porque dependiendo de la máscara, por ejemplo una con valor 026, puede ocurrir que el usuario anónimo suba un fichero al servidor y este no sea universalmente accesibe. En ese caso, aunque el usuario anónimo haya subido el fichero, no podrá ser descargado luego por él. .. _ftp-usuarios: Usuarios locales ---------------- Los :dfn:`usuarios locales`, esto es, los usuarios registrados y con capacidad de autenticación en el sistema, están habilitado por defecto gracias a la directiva:: local_enable=YES Al ingresar en el sistema entraran en su directorio personal, pero a diferencia del usuario *anónimo*, tienen libertad para consultar todo la parte del sistema de ficheros accesible según sus permisos, en vez de estar enjauladas dentro de él. Más adelante veremos cómo alterar esto. Para habilitar sus permisos de escritura es necesaria la directiva:: write_enable=YES No obstante lo anterior, es posible alterar el directorio de ingreso mediante la directiva:: local_root=/home que provocaría que todos los usuarios locales accedieran a :file:`/home/` en vez de a su directorio personal. No obstante, puede particularizarse el valor de esta directiva ayudándose de ``user_sub_token``, del siguiente modo:: user_sub_token=$USER local_root=/srv/ftp/$USER de este modo, cada usuario podrá estar localizado en un directorio diferente sin ser el que indica su información de usuario. Otra forma de particularizar, aunque en este caso no sólo para indicar el directorio de usuario es la directiva ``user_config_dir`` que permite definir un directorio de configuraciones personalizadas. Si un fichero de ese directorio tiene el nombre de un usuario, se cargara la configuración contenida en él para ese usuario. Por ejemplo:: user_config_dir=/etc/vsftpd y además creamos el fichero:: # cat > /etc/vsftpd/pepe local_root=/srv/ftp/pepe_es_un_chico_especial write_enable=NO local_max_rate=10024 Al usuario *pepe* y sólo a él, se le aplican las directivas incluidas en el fichero, que sobreescribirán a la que puedan encontrarse en el fichero general. Enjaulado --------- Los usuarios locales también pueden ser enjaulados:: chroot_local_user=YES No obstante, la configuración nos permite establecer un fichero de excepciones a la política predeterminada con:: chroot_list_enable=YES chroot_list_file=/etc/vsftpd.jail En tal fichero, puede incluirse los usuarios, uno por línea, que **no** siguen la política de enjaulamiento general. Es importante, entender que estos usuarios son la excepción, por lo que representan los enjaulados si ``chroot_local_user`` está deshabilitado y los no enjaulados, si está habilitada. Un aspecto muy importante al enjaular los usuarios es que .. warning:: Por motivos de seguridad, el usuario enjaulado no puede tener permisos de escritura sobre el directorio de enjaulamiento. Esto provoca un problema, sobre todo para usuarios locales, porque lo habitual es que los usuarios requieran permisos de escritura sobre sus propios directorios, si acceden al sistema por otros medios. En principio, tenemos cuatro posibles soluciones: #. Enjaular a los usuarios dentro de :file:`/home`, para lo cual basta con:: local_root=/home Esta solución tiene la desventaja de que el usuario puede ver qué usuarios están definidos en el sistema y dependiendo de los permisos de los directorios del resto, podría meterse en algunos ajenos. #. Eliminar los permisos de escritura de los directorios personales, lo cual puede llegar a ser un problema, si los usuarios acceder con otros servicios (|SSH|, por ejemplo). #. Enjaular al usuario en un directorio exclusivo distinto al personal. Tiene dos variantes: * Que el directorio nada tenga que ver el directorio personal:: user_sub_token=$USER local_root=/srv/ftp/$USER si suponemos claro, que los directorios personales son los habituales :file:`/home/nombre_usuario`. * Otra variante es hacer que el directorio de enjaulamiento sea un subdirectorio del directorio personal:: user_sub_token=$USER local_root=/home/$USER/ftp .. note:: Por supuesto, si queremos subir ficheros, será necesario haber creado un subdirectorio dentro con permisos de escritura. Por ejemplo:: $ mkdir -p ~/ftp/incoming $ chmod 555 ~/ftp #. Añadir la opción (no documentada en la página de manual):: allow_writeable_chroot=YES que, directamente, permite enjaular a un usuario dentro de un directorio en el que tiene permisos de escritura. La directiva apareció en la versión *2.3.5*, después que desde la versión *2.3.4* se pasara a comprobar el permiso de escritura sobre el directorio de la jaula. Esto, sin embargo, se desaconseja, porque hace vulnerable el servidor a `un ataque contra su seguridad `_. En cualquier caso, esta directiva sólo se aplica a usuarios no anónimos. .. _ftp-acceso: Restricciones de acceso ----------------------- Entendemos por ello la posibilidad de prohibir el acceso |FTP| a ciertos usuarios, que en principio tienen acceso al servidor. Para lograrlo hay dos vías: * Cambiar la configuración del servidor (o sea editar :file:`/etc/vsftpd.conf`). * Influir en el proceso de autenticación, que es una herramienta más poderosa y da pie a una restricción mucho más rica. Analicemos ambas vías. Mediante configuración """""""""""""""""""""" Las directivas:: userlist_enable=YES userlist_file=/etc/vsftpd.userlist permiten definir un fichero en el que pueden incluirse usuarios a los que se quiere o negar o permitir en exclusividad el acceso. Que nuestra política de accesos sea de lista blanca o negra depende del valor de otra directiva:: userlist_deny=NO Deshabilitada, la política será de lista blanca y el fichero contendrá los únicos usuarios capaz de usar el servidor; habilitada la política será de lista negra. .. note:: Nótese que sólo permite la inclusión de nombres de usuario, no de grupos. Para una configuración más flexible debe optarse por manipular la autenticación. Mediante autenticación """""""""""""""""""""" :program:`vsftpd` se vale para la autenticación con :ref:`pam ` para permitir el acceso al servidor. De hecho, la directiva ``pam_service_name`` nos permite indicar cuál es el nombre del servicio para |PAM|. Su valor predeterminado es *vsftpd* y es es la razón por la que existe :file:`/etc/pam.d/vsftpd` para controlar la autenticación: .. literalinclude:: files/vsftpd :language: bash :emphasize-lines: 2, 10 Este es un contenido. Como vemos a la autenticación común a todos los servicios, se añaden dos requisitos más: * Que el usuario tenga definida una *shell* válida (módulo *pam_shell.so*). * Que el usuario no este listado en el fichero :file:`/etc/ftpusers`. Esa es la razón la qu el usuario administrador no puede acceder por |FTP| al servidor:: # grep root /etc/ftpusers root La restricción en el acceso mediante este método puede ser tanta como nos permita nuestro conocimiento de |PAM|. Por ejemplo, podríamos añadir una primera línea como esta:: auth required pam_listfile.so item=group sense=allow file=/etc/ftpgroups onerr=succeed que permitiría crear un fichero donde incluyéramos los grupos de usuarios a los que exclusivamente permitiéramos el acceso al |FTP|. Si esto lo complementáramos con:: # cat > /etc/ftpgroups ftpusers resultaría en que sólo los usuarios pertenecientes al grupo *ftpusers* serán capaces de acceder al servidor. .. _ftp-limitaciones: Limitaciones de uso ------------------- Disponemos de toda una serie de directivas relacionadas con las limitaciones de uso del servidor:: local_max_rate=10240 permitir limitar la velocidad en bytes/segundo a la que los usuarios locales pueden subir o bajar ficheros:: max_clients=5 limita el número máximo de conexiones simultáneas; mientras que:: max_per_ip=2 limita el númnero máximo de conexiones por *IP*. En ambos casos, **0** significa que no hay límite y justamente ése es el valor predeterminado. En principio, no hay directiva para limitar el acceso por usuarios (o grupos), pero la directiva:: session_support=YES provoca que la sesión se apunte en :file:`/var/log/wtmp` y, consecuentemente, que las limitaciones ``maxlogins`` y ``maxsyslogins`` propiciadas por el módulo *pam_limits.so* tengan efecto. Para ver cómo hacerlo, puede consultar la :ref:`discusión sobre limitaciones al acceso SSH `. Conexión segura --------------- Como todos los viejos protocolos, |FTP| no presta atención a la seguridad y la contraseña viaja en claro a través de la red. Para subsanarlo es posible embucharlo en una negociación |SSL| (o |TLS| como se prefiera decir), para lo cual se requiere antes la creación de un certificado digital. .. note:: Consulte la :ref:`creación de un certificado ` que se expone en la parte dedicada al tráfico web. Sirve tanto el certificado autofirmado como el obtenido con *Let's Encrypt*. Obtenido el certificado, podemos optar por cifrar: * ambos canales o sólo el canal de control y no el de datos. * sólo la conexión para los usuarios locales o también para el usuario anónimo. Un ejemplo de configuración en el que intervienen las directivas relativas a la seguridad es esta:: # Sólo ciframos comunicación de los usuarios locales. ssl_enable=YES allow_anon_ssl=NO # Sólo forzamos el cifrado del canal de control force_local_data_ssl=NO force_local_logins_ssl=YES # Ciframos usando TTLv1.0 que es más seguro que SSLv3 ssl_tlsv1=YES ssl_sslv2=NO ssl_sslv3=NO # Certificado digital (suponemos el autofirmado) rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key .. note:: También hay un ``force_anon_data_ssl`` y un ``force_anon_logins_ssl`` para cifrar de manera independiente los canales de control y datos de la conexión anónima. .. note:: Con esta configuración, :file:`vsftpd` usa cifrado explícito (llamado |FTPES|), es decir, hay una negociación previa en la que el servidor obliga al cliente a que cifre el canal de control (debido al valor de :kbd:`force_local_logins_ssl` ) y se cifre con |TLS| (véase :ref:`STARTTLS `). Tambien éxiste el cifrado implícito (|FTPS|), que es más antiguo y se habilita con la opción:: implicit_ssl=YES listen_port=990 y en el que no hay negociación previa, sino que directamente se establece el protocolo |TLS| para asegurar la comunicación y dentro de él se comienza una sesión |FTP| tradicional. Cuando se usa este segundo método de cifrado, la escucha se suele hacer por el puerto **990**, de ahí que hayamos incluido la directiva para cambiar el puerto de escucha. Cuando se usa |FTPES|, no es necesario declarar nada, puesto que la escucha es el el puerto **21** y el cifrado es consecuencia de una negociación. Con el implícito, en cambio, si que es necesario declararlo (generalmente con :kbd:`ftps://`) ya que el cliente tiene que cambiar de puerto y además empezar directamente el protocolo |TLS|. En cualquier caso, lo recomentable es usar |FTPES|. .. warning:: Al cifrar la comunicación, necesitaremos un cliente que la soporte. El cliente |FTP| habitual en los *UNIX* no lo hace. Podemos, en su sustitución, usar :program:`ftp-ssl`, o :program:`lftp` que, además de soportar cifrado, tiene una interfaz de texto mucho más potente. En entorno gráfico (y sistemas *Windows*), :program:`FileZilla` soporta tanto |FTPES| como |FTPS|. Cuota ===== .. seealso:: Consulte cómo crear :ref:`cuotas de disco `. .. _ftp-virtuales: Usuarios virtuales ================== Hasta ahora hemos configurado el servidor para que sea utilizado por usuarios que, además, tienen acceso al resto de servicios. El propósito, a partir de ahora, es crear usuarios cuyo único propósito es el acceso al |FTP|, por lo que no serán válidos para el resto de los servicios. Haremos dos aproximaciones. .. _ftp-pseudo-virtuales: Falsamente virtuales -------------------- Los denominados :dfn:`falsamente virtuales`, porque no son virtuales, ya que son usuarios que realmente existen en el sistema ,es decir, que :kbd:`getent passwd` los reconoce. A pesar de ello, manipulamos la autenticación para que sean incapaces de autenticarse en ningún otro servicio. La tarea, por tanto, se reduce a configurar |PAM| para lograrlo. Lo primero es caracterizar a tales usuarios de manera que sólo ellos cumplan el requisito que establezcamos. Por ejemplo, que sean los únicos que se encuentren dentro de un rango de |UID|\ s o que los únicos que pertenecen a un grupo determinado. Este último criterio es el más fácil de implementar así que crearemos un grupo nuevo:: $ addgroup --system ftponly y añadiremos a él los usuarios de |FTP| *falsamente virtuales*. Una manera bastante limpia de impedirle el acceso al resto de usuarios es crear :download:`este fichero ` en :file:`/usr/share/pam-configs/ftponly`: .. literalinclude:: files/ftponly :language: bash Esto propicia que ejecutando :program:`pam-auth-update`: .. image:: files/pam-auth-update_menu.png podamos añadir (o quitar) cómodamente las siguientes líneas a :file:`/etc/pam.d/common-account`:: account [success=1 default=ignore] pam_succeed_if.so service = vsftpd account required pam_listfile.so item=group sense=deny onerr=succeed file=/etc/ftponly account required pam_permit.so que impide que cualquier usuario perteneciente a un grupo incluido en el fichero :file:`/etc/ftponly` pueda autenticarse en un servicio que no sea *vsftpd*\ [#]_. Por supuesto, deberemos añadir el grupo *ftponly* al fichero:: # echo "ftponly" > /etc/ftponly .. _ftp-virtuales-feten: Realmente virtuales ------------------- Como sí son virtuales, no existen en el sistema, sino únicamente en la autenticación del servidor |FTP|. Esto provoca que no tengan más que un nombre de usuario y una contraseña, y que carezcan del resto de características que requiere un usuario real (|UID|, grupo principal, etc.). Consecuentemente, el servidor debe mapear los usuarios virtuales a un usuario real cuando estos realizan una acción en el servidor (p.e. crear un fichero en el sistema de fichero al subirlo). Para utilizar usuarios realmente virtuales son necesarias tres tareas diferenciadas: * Crear y almacenar sus nombres y contraseñas. * Manipular la autenticación. * Configurar :program:`vsftpd` para poder utilizarlos. Creación """""""" Para la creación de los usuarios podemos crear una base de datos *Berkeley* (para luego usarla con *pam_userdb.so*), o un fichero con formato semejante al de :file:`/etc/passwd`. Usaremos el primer método\ [#]_ para lo cual, debe seguirse lo expuesto para :ref:`la creación de usuarios del correo electrónico `. Autenticación """"""""""""" Basta con añadir las dos siguientes líneas al comienzo de :file:`/etc/pam.d/vsftpd`:: # Usuarios virtuales auth sufficient pam_userdb.so db=/etc/vsftpd_users crypt=crypt account sufficient pam_userdb.so db=/etc/vsftpd_users Configuración """"""""""""" Los usuarios virtuales son llamados *invitados* en la configuración. Para habilitarlos es necesario al menos incluir en :file:`/etc/vsftpd.conf`:: guest_enable=YES que provoca que los usuarios se mapeen al usuario que indique ``guest_username`` y que por defecto es *ftp*. Pero: .. warning:: Todos los usuarios, incluidos los reales, se mapean. Además, los usuarios se tratan como el usuario anónimo: enjaulamiento, permisos, etc. Si se quiere que se traten tal como indican las directivas relativas a usuarios locales debe incluirse:: virtual_use_local_privs=YES .. note:: Al mapearse todos los usuarios a *ftp*, el directorio de ingreso será :file:`/srv/ftp` que es el directorio personal de tal usuario. Lo que puede hacerse para subsanarlo es particularizar el directorio de ingreso con alguno de los métodos ya descritos, por ejemplo:: user_sub_token=$USER local_root=/home/$USER .. rubric:: Notas al pie .. [#] Obviamente exige la instalación y configuración del superservidor (el paquete trae un fichero de ejemplo para :program:`xinetd`). .. [#] Téngase en cuenta de que, si se cambia el nombre del servicio con ``pam_service_name``, habrá que editar el fichero. .. [#] Aunque el módulo se incluye dentro del paquete de módulos de |PAM| ya instalados, requiere la instalación del paquete *db-util*. El segundo método requiere la instalación del paquete *libpam-pwdfile*. El segundo método, además, permite añadir el resto de la información de usuario, no sólo la contraseña, pero dado que :program:`vsftpd` no hace uso de ello, no supone ninguna ventaja. .. |SSL| replace:: :abbr:`SSL (Secure Socket Layer)` .. |TLS| replace:: :abbr:`TLS (Transport Layer Security)` .. |FTPS| replace:: :abbr:`FTPS (FTP Secure)` .. |FTPES| replace:: :abbr:`FTPES (FTP Explicit Secure)` .. |UID| replace:: :abbr:`UID (User IDentifier)`