While chroot_local_user=YES
in vsftpd appears to restrict users to their home directories, it creates a fundamental security vulnerability due to Linux's filesystem permissions model. When chroot is applied, the user still retains ownership of their files, which can lead to privilege escalation paths.
# Example of dangerous permission structure: drwxr-xr-x 3 ftpuser ftpgroup 4096 Jan 1 10:00 /home/ftpuser -rw-r--r-- 1 ftpuser ftpgroup 0 Jan 1 10:00 /home/ftpuser/.bashrc
Your intuition about SSH is correct - disabling shell access via /etc/passwd
helps but doesn't fully solve the issue:
# In /etc/passwd: ftpuser:x:1001:1001::/home/ftpuser:/usr/sbin/nologin
However, the chroot vulnerability still exists because:
- FTP users could potentially upload malicious scripts
- World-readable system files might be accessible through symlink attacks
- Configuration errors in vsftpd could lead to escapes
For production systems, consider these robust alternatives:
1. Using Virtual Users with Proper Jail
Create virtual users with PAM and enforce proper chroot through vsftpd's jail mechanism:
# /etc/vsftpd.conf anonymous_enable=NO local_enable=YES write_enable=YES chroot_local_user=YES allow_writeable_chroot=YES user_sub_token=$USER local_root=/var/ftp/$USER
2. Implementing Filesystem Namespaces
For modern Linux systems, using mount namespaces provides better isolation:
# Create dedicated mount namespace unshare --mount --user --map-root-user --fork --pid mount --bind /home/ftpuser /home/ftpuser mount -o remount,rw,nosuid,nodev,bind /home/ftpuser
3. Container-based Solution
For maximum security, run vsftpd in a container with properly configured volumes:
# Docker example docker run -d \ --name secured-ftp \ -p 21:21 \ -v /path/to/ftp_data:/home/ftpuser \ -e FTP_USER=ftpuser \ -e FTP_PASS=password \ --cap-drop=ALL \ fauria/vsftpd
Even with chroot, implement these permission controls:
# Secure directory structure: chown root:root /home/ftpuser chmod 755 /home/ftpuser mkdir /home/ftpuser/files chown ftpuser:ftpgroup /home/ftpuser/files chmod 750 /home/ftpuser/files
This creates a root-owned parent directory with restricted access to the actual user content area.
While chroot_local_user=YES
seems like a straightforward solution for restricting FTP users to their home directories, it introduces several security vulnerabilities:
# Example vulnerable vsftpd.conf configuration listen=YES anonymous_enable=NO local_enable=YES write_enable=YES chroot_local_user=YES
The primary security issues stem from:
- Write permission requirements: vsftpd requires the chroot directory to be writable when using chroot_local_user
- Potential privilege escalation: Users can create hard links to system files before chroot is applied
- Incomplete isolation: The chroot jail can be broken through various techniques
Even if you disable SSH access for these users, the FTP-specific vulnerabilities remain:
# Disabling SSH in /etc/ssh/sshd_config DenyUsers ftpuser1 ftpuser2 Match User ftpuser* ChrootDirectory %h ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no
Consider these more robust approaches:
Option 1: Using chroot_list
# Secure vsftpd.conf configuration chroot_local_user=NO chroot_list_enable=YES chroot_list_file=/etc/vsftpd.chroot_list allow_writeable_chroot=YES
Option 2: Combined with SFTP
# /etc/ssh/sshd_config configuration Subsystem sftp internal-sftp Match Group sftpusers ChrootDirectory /home/%u ForceCommand internal-sftp PermitTunnel no AllowAgentForwarding no AllowTcpForwarding no X11Forwarding no
Option 3: Proper Directory Structure
Create a secure directory hierarchy:
sudo mkdir -p /var/ftp/users/user1/{uploads,downloads} sudo chown -R root:root /var/ftp/users/user1 sudo chmod -R 755 /var/ftp/users/user1 sudo mkdir /var/ftp/users/user1/uploads sudo chown user1:user1 /var/ftp/users/user1/uploads
Here's a complete secure setup:
# vsftpd.conf listen=YES anonymous_enable=NO local_enable=YES write_enable=YES chroot_local_user=NO chroot_list_enable=YES chroot_list_file=/etc/vsftpd.chroot_list allow_writeable_chroot=YES user_sub_token=$USER local_root=/var/ftp/users/$USER pasv_min_port=40000 pasv_max_port=50000
Create the chroot list:
sudo touch /etc/vsftpd.chroot_list sudo chmod 600 /etc/vsftpd.chroot_list
For production environments, consider:
- Implementing TLS encryption
- Setting up rate limiting
- Using fail2ban for brute force protection
- Regularly auditing file permissions
Remember that security is an ongoing process, not a one-time configuration. Always test your setup thoroughly before deploying to production.