Vấn đề thực tế gặp phải: Cấp quyền upload file nhưng lộ cả hệ thống
Khoảng hơn nửa năm trước, team mình nhận một dự án outsourcing cho đối tác. Họ cần một tài khoản để định kỳ đẩy dữ liệu backup và file hình ảnh lên VPS Ubuntu. Như thói quen thông thường, một bạn junior tạo tài khoản Linux, cấp mật khẩu rồi gửi cho bên thứ ba để họ dùng FileZilla đẩy file qua SFTP.
Mọi chuyện tưởng chừng êm đẹp cho tới một ngày mình kiểm tra nhật ký truy cập. Khách hàng tò mò gõ thử lệnh SSH bằng terminal và nhận ra họ có thể đứng từ thư mục home gõ cd /etc, xem danh sách service qua ps aux, thậm chí đọc được kha khá file cấu hình nhạy cảm khác trên hệ thống. Dù họ không có quyền root để sửa đổi phá hoại, việc một người lạ đi lại tự do trong cấu trúc file hệ điều hành là một lỗ hổng an ninh khó chấp nhận được.
Phân tích nguyên nhân: Bản chất của SFTP mặc định
SFTP (SSH File Transfer Protocol) vốn là một subsystem chạy ngầm trên nền SSH (OpenSSH). Khi tạo một tài khoản user bình thường trên Ubuntu, mặc định hệ thống sẽ:
- Gán một shell hợp lệ (thường là
/bin/bashhoặc/bin/sh). - Đặt quyền đọc (read) trên hầu hết các thư mục cấp hệ thống như
/var/log,/etc,/usrcho nhómothers.
Do đó, khi đăng nhập bằng công cụ SFTP như WinSCP hay FileZilla, người dùng hoàn toàn có thể nhấn nút “lên một cấp thư mục” (..) để duyệt toàn bộ ổ đĩa gốc /. Nếu họ dùng terminal gõ ssh user@ip, họ sẽ có ngay một session bash đầy đủ quyền hạn của một người dùng thông thường.
Các cách giải quyết bài toán chia sẻ file an toàn
Khi đối mặt với yêu cầu: “Cho phép bên ngoài đẩy file lên server nhưng tuyệt đối không được xem trộm dữ liệu khác”, mình đã cân nhắc ba phương án:
1. Dùng FTP thuần hoặc FTPS (vsftpd)
Đây là giải pháp truyền thống. Cài vsftpd, bật tính năng local_enable và chroot. Tuy nhiên, nhược điểm là bạn phải mở thêm port (21 và dải passive port), cấu hình tường lửa phức tạp hơn và quản lý thêm một dịch vụ daemon độc lập chạy ngầm trên VPS.
2. Dùng WebDAV hoặc dịch vụ Object Storage
Dựng Nextcloud, MinIO hoặc đẩy trực tiếp qua S3-compatible storage. Cách này rất sạch sẽ cho hạ tầng, nhưng lại quá tải với các nhu cầu nhỏ lẻ, đồng thời đối tác quen dùng các phần mềm FTP client cổ điển sẽ gặp khó khăn khi thao tác tự động bằng script.
3. Cấu hình SFTP Chroot Jail với OpenSSH
Tận dụng trực tiếp OpenSSH có sẵn trên Ubuntu Server. Khóa user vào đúng một thư mục định sẵn (Chroot Directory) và tắt hoàn toàn quyền truy cập interactive shell (nologin). Người dùng chỉ có thể truyền file, không SSH được, và đứng từ góc nhìn của họ, thư mục được phân quyền chính là thư mục gốc / của toàn bộ server.
Cách tốt nhất: Hướng dẫn cấu hình SFTP Chroot Jail trên Ubuntu
Mình đã cài Ubuntu Server 22.04 trên hơn 20 con VPS và quy trình này là cách mình luôn làm đầu tiên mỗi khi cần cấp quyền cho bên thứ ba tải dữ liệu lên server. Nó không cần cài thêm bất kỳ phần mềm nào ngoài OpenSSH có sẵn, bảo mật cao và chạy ổn định tuyệt đối suốt nửa năm qua trên production.
Bước 1: Tạo Group riêng cho người dùng SFTP
Gom tất cả các tài khoản cần giới hạn vào một nhóm (ví dụ sftp_users) để dễ dàng quản lý quyền hạn tập trung trong file cấu hình SSH:
sudo groupadd sftp_users
Bước 2: Tạo User mới và khóa Shell đăng nhập
Tạo một user mới tên là uploaduser. Điểm mấu chốt ở đây là gán shell /usr/sbin/nologin (hoặc /bin/false) để ngăn chặn hoàn toàn việc mở terminal SSH:
sudo useradd -m -g sftp_users -s /usr/sbin/nologin uploaduser
sudo passwd uploaduser
Nhập mật khẩu an toàn cho tài khoản này.
Bước 3: Cấu hình OpenSSH Subsystem
Mở file cấu hình SSH Daemon:
sudo nano /etc/ssh/sshd_config
Tìm dòng cấu hình Subsystem sftp mặc định và đổi thành internal-sftp. Cuối file, thêm block cấu hình riêng cho group sftp_users:
# Tìm và comment dòng cũ nếu có, đổi thành:
Subsystem sftp internal-sftp
# Thêm vào cuối file sshd_config:
Match Group sftp_users
ChrootDirectory /var/sftp/%u
ForceCommand internal-sftp
X11Forwarding no
AllowTcpForwarding no
PasswordAuthentication yes
Giải thích các tham số:
Match Group sftp_users: Áp dụng các luật bảo mật bên dưới cho bất kỳ ai thuộc nhóm này.ChrootDirectory /var/sftp/%u: Khóa user vào thư mục/var/sftp/uploaduser. Biến%utự động lấy theo username.ForceCommand internal-sftp: Ép buộc chạy trình xử lý sftp ngay khi kết nối thành công, không sinh shell.X11Forwarding novàAllowTcpForwarding no: Chặn tính năng port forwarding và đồ họa để tránh bị lợi dụng làm proxy.
Bước 4: Phân quyền thư mục Chroot (Cực kỳ quan trọng)
Đây là bước khiến nhiều người đau đầu nhất và hay gặp lỗi “Connection reset by peer” hoặc “Permission denied”. Cơ chế bảo mật của OpenSSH yêu cầu:
Thư mục ChrootDirectory PHẢI thuộc sở hữu của root và KHÔNG AI KHÁC ĐƯỢC PHÉP GHI VÀO THƯ MỤC ĐÓ.
Do đó, chúng ta sẽ tạo cấu trúc: thư mục ngoài cùng do root sở hữu, bên trong tạo một thư mục con tên là files do chính uploaduser làm chủ để họ upload dữ liệu:
# Tạo cấu trúc thư mục giam giữ
sudo mkdir -p /var/sftp/uploaduser/files
# Đảm bảo thư mục jail thuộc sở hữu root:root và quyền 755
sudo chown root:root /var/sftp/uploaduser
sudo chmod 755 /var/sftp/uploaduser
# Cấp quyền cho user sở hữu thư mục upload con
sudo chown uploaduser:sftp_users /var/sftp/uploaduser/files
sudo chmod 775 /var/sftp/uploaduser/files
Bước 5: Kiểm tra cấu hình và khởi động lại SSH
Trước khi khởi động lại SSH, luôn dùng lệnh kiểm tra cú pháp để tránh bị lock khỏi server nếu lỡ gõ sai dấu:
sudo sshd -t
Nếu lệnh không báo lỗi gì, tiến hành restart SSH service:
sudo systemctl restart ssh
Bước 6: Kiểm tra kết quả thực tế
Bây giờ đứng từ máy client của bạn để kiểm tra hai kịch bản:
1. Thử đăng nhập SSH thông thường:
ssh uploaduser@your_server_ip
Server sẽ trả về thông báo: This account is currently not available. hoặc đóng kết nối ngay lập tức. User không thể lấy được terminal.
2. Đăng nhập qua SFTP:
sftp uploaduser@your_server_ip
Kết nối thành công! Thử kiểm tra thư mục hiện tại:
sftp> pwd
Remote working directory: /
sftp> ls
files
sftp> cd ..
sftp> pwd
Remote working directory: /
Dù gõ cd .. bao nhiêu lần thì user vẫn chỉ nhìn thấy thư mục ảo /, bên trong có thư mục files để upload. Toàn bộ file hệ thống của Ubuntu đã được bảo vệ hoàn toàn khỏi tầm mắt của đối tác bên ngoài.

