本文環境:CentOS 7
簡介
FTP(文件傳輸協議,File Transfer Protocol)是最古老的協議之一,誕生於1971年,距今已經半個世紀了,它的目的是在不同計算機之間傳輸文件(實現跨平台傳輸),工作於TCP/IP協議的應用層,需要注意的是,FTP以明文方式傳輸。
聲明:下文出現的鏈接是名詞,表示端口到端口之間的虛擬鏈路;而連接是動詞,表示建立鏈路的這個動作,連接 = 建立鏈接。
工作流程簡介
FTP使用兩個端口同時進行通信,即控制鏈接和數據連接,它們都基於TCP協議,控制鏈接端口默認是21,數據鏈接默認端口是20,控制鏈接用來傳輸用戶名、密碼、傳輸方式等,而數據連接就是用來傳輸真實的文件數據,所以客戶端和服務端都同時運行着控制鏈接進行和數據連接進行,一般而言,客戶端首先向服務器發起控制連接請求,服務器的控制鏈接默認監聽21端口,同時告訴服務器自己的一個空閑端口號,用於之后傳輸數據,然后,服務器通過默認的20端口和客戶機所提供的空閑端口建立起數據鏈接,至此整個FTP鏈接全部建立,可以開始傳輸數據了。
默認情況下,控制鏈接在整個FTP會話期間一直存在,但數據鏈接在每次傳輸完文件后會自動斷開,繼續傳文件需要重新建立數據鏈接。
FTP的數據傳輸格式
ASCII或BINARY,即以文本方式傳輸還是以二進制方式傳輸,以文本方式傳輸會自動轉換一些特殊字符,如,Windows向Linux以文本方式傳輸文件下會把CRLF轉為LF,整個FTP傳輸的過程以字符流或比特流傳輸。
服務器應答格式(由三位數字組成)
第一位數字:
1XX 確定預備應答:在發送一個命令前期待另一個命令應答
2XX 確定完成應答:要求的操作已經完成,可以接受新的命令了
3XX 確定中間應答:此命令已被接受,但在處理前,還需要另一個命令
4XX 暫時拒絕完成應答:請求的命令被拒絕,但是只是暫時的,可以稍后重發此命令再次嘗試
5XX 永久拒絕應答:請求的命令被拒絕,並且要求不再重試
第二位數字:
X0X 語法錯誤
X1X 一般性的解釋信息
X2X 與控制和數據鏈接有關
X3X 與認證和賬號登入有關
X4X 保留
X5X 與文件系統有關
第三位數字是在第二個數字的基礎上對應答做進一步細化,沒有具體的規定,但是,有些約定成文的常見應答,如下,
125 數據鏈接已經打開,開始傳輸
200 就緒
214 面向用戶的幫助信息
331 用戶名已接收,等待密碼輸入
425 不能打開數據鏈接
452 寫文件出錯
500 語法錯誤(未知的命令)
501 語法錯誤(參數錯誤)
數據連接的主動和被動
數據鏈接的建立分為主動方式和被動方式,具體選擇哪種方式由客戶端決定,客戶端在上傳或下載文件時要先發送一個PORT或PASV命令,表示采用主動方式還是被動方式,需要注意的是,主動和被動是相對於服務器而言的:如果數據連接由服務器先發起,則為主動方式;如果數據連接由客戶機先發起,則為被動方式。
主動方式下,客戶端首先通過PORT命令向服務器發送自己的一個空閑端口號(大於1024),然后服務器通過默認的20端口向客戶端提供的端口建立數據鏈接。
被動方式下,客戶端先向服務器發送PASV命令,服務器會回應一個它空閑的端口號(定義在主配置文件中的passv_min_port和passv_max_port兩個配置項指定的閉區間),告訴客戶端它將在這個端口監聽來自客戶端的數據鏈接建立請求,最后,客戶端選擇一個空閑端口(大於1024)向服務器的這個端口建立數據鏈接。
vsftp服務器端配置
本文以vsftp(very secure ftp)軟件來配置服務器端的FTP服務,著名的Red Hat、SUSE、Debian、GNU等都是使用這款軟件來部署它們的FTP服務器。
第一步:在服務器端安裝vsftpd軟件
有三種安裝方式,編譯源碼安裝、使用RPM包安裝和使用YUM源安裝,這里使用YUM 源安裝,這種方式安裝前請確保已正確配置YUM源,
[root@localhost ~]# yum -y install vsftpd
第二步:在客戶端安裝ftp軟件
也有三種安裝方式,這里使用YUM,
[root@localhost ~]# yum -y install ftp
第三步:測試匿名用戶是否能登入
先開啟服務端的vsftp服務,
[root@localhost ~]# systemctl start vsftpd
關閉服務端的防火牆和SELinux,
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# setenforce 0
在客戶端輸入“ftp 服務器的地址”進行測試,其中匿名用戶登入的用戶名是anonymous, 密碼可以為空,也可以是任意字符串,
[root@localhost ~]# ftp 192.168.88.128
Connected to 192.168.88.128 (192.168.88.128).
220 (vsFTPd 3.0.2)
Name (192.168.88.128:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
輸入quit命令即可退出ftp回到原來的Shell,
ftp> quit
221 Goodbye.
第三步:配置本地FTP用戶
首先創建一個本地賬戶,
[root@localhost ~]# useradd -s /sbin/nologin -g ftp ftptest1
為這個用戶配置密碼,這里密碼設為123,
[root@localhost ~]# echo 123 | passwd --stdin ftptest1
Changing password for user ftptest1.
passwd: all authentication tokens updated successfully.
回到客戶端,使用之前的方法進行測試,
[root@localhost ~]# ftp 192.168.88.128
Connected to 192.168.88.128 (192.168.88.128).
220 (vsFTPd 3.0.2)
Name (192.168.88.128:root): ftptest1
331 Please specify the password.
Password:
530 Login incorrect.
Login failed.
ftp>
這里出現了一個問題,即便密碼輸入正確,依舊顯示登入失敗,這時由於PAM模塊驗 證機制導致的(PAM會阻止那些是nologin shell的用戶登入FTP服務),解決這個問題 有兩個辦法,第一個是創建一個具有登入shell(如bash)的用戶,但是這樣會產生安 全問題,第二個是找到PAM模塊,將其對FTP驗證的功能關閉,這里使用第二個方法,
[root@localhost ~]# vim /etc/pam.d/vsftpd
然后將包含”pam_shells.so”這行注釋,前面添加#進行注釋,
#auth required pam_shells.so
重啟vsftpd服務,然后再回到客戶端繼續嘗試登入,
[root@localhost ~]# ftp 192.168.88.128
Connected to 192.168.88.128 (192.168.88.128).
220 (vsFTPd 3.0.2)
Name (192.168.88.128:root): ftptest1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
登入成功,使用pwd命令查看所在的FTP服務器的路徑,
ftp> pwd
257 "/home/ftptest1"
發現可以查看到完整路徑名(從根開始),這是很不安全的
第四步:限定用戶的登入目錄
找到vsftpd的主配置文件並打開,
[root@localhost ~]# vim /etc/vsftpd/vsftpd.conf
將其中的”#chroot_local_user=YES”取消注釋,然后重啟服務,再去客戶端登入,
[root@localhost ~]# ftp 192.168.88.128
Connected to 192.168.88.128 (192.168.88.128).
220 (vsFTPd 3.0.2)
Name (192.168.88.128:root): ftptest1
331 Please specify the password.
Password:
500 OOPS: vsftpd: refusing to run with writable root inside chroot()
Login failed.
421 Service not available, remote server has closed connection
ftp>
又出現錯誤了,大致意思是:拒絕一個帶有寫權限的根目錄,為什么呢?這是因為vsftp 是一個很安全的FTP服務軟件,所以,如果一個用戶的登入目錄被限制了,那么他的登 入目錄不應該再有寫的權限,我們來看看ftptest1的登入目錄(也就是他的家目錄),
[root@localhost ~]# ll -d /home/ftptest1/
drwx------. 2 ftptest1 ftp 62 Dec 18 15:11 /home/ftptest1/
可以發現,ftptest1確實對他自己的家目錄有寫的權限,怎么解決呢?也有兩個解決方 法,第一個是使用chmod命令將這個目錄的寫權限去掉,第二個是修改主配置文件, 這里選擇第二個方法,在主配置文件中添加下行,
allow_writeable_chroot=YES
然后重啟服務,
[root@localhost ~]# ftp 192.168.88.128
Connected to 192.168.88.128 (192.168.88.128).
220 (vsFTPd 3.0.2)
Name (192.168.88.128:root): ftptest1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/"
ftp>
問題成功解決,並且用戶的登入已經被限制了
第五步:FTP黑名單
vsftpd存在一個全局黑名單,是/etc/vsftpd/ftpusers,將用戶添加到這個文件(每個用戶 名占一行),那么,即便用戶輸對了密碼,也提示密碼錯誤,除了這個黑名單,vsftpd 還存在另一個黑名單,是/etc/vsftpd/user_list(也是每個用戶占一行),開啟這個黑名單 需要修改主配置文件,確保userlist_enable的值是YES,如下,
userlist_enable=YES
位於user_list文件中的用戶,一旦輸入用戶名,直接被拒絕,連輸入密碼的機會都沒有, 更新user_list或ftpusers都不需要重啟vsftpd服務。
第六步:上傳和下載
先將上一步中的ftptest1用戶從全局黑名單和user_list黑名單中移除,然后在這個用戶 的登入目錄新建一個文件夾為pub,權限為777,作為共用目錄,
[root@localhost ~]# mkdir /home/ftptest1/pub
[root@localhost ~]# chmod 777 /home/ftptest1/pub/
[root@localhost ~]# ll -d /home/ftptest1/pub/
drwxrwxrwx. 2 root root 6 Dec 18 15:40 /home/ftptest1/pub/
然后在這個目錄里面創建一個文件,用於客戶端的下載,
[root@localhost ~]# echo "hello I am from vsftpd" > /home/ftptest1/pub/readme.txt
回到客戶端,在/tmp下創建一個文件,用於上傳,
[root@localhost ~]# echo "2019" > /tmp/example.txt
打開ftp,連接到服務器,查看、下載到客戶端的tmp目錄和上傳到服務器的pub目錄,
[root@localhost ~]# ftp 192.168.88.128
Connected to 192.168.88.128 (192.168.88.128).
220 (vsFTPd 3.0.2)
Name (192.168.88.128:root): ftptest1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/"
ftp> ls
227 Entering Passive Mode (192,168,88,128,51,1).
150 Here comes the directory listing.
drwxrwxrwx 2 0 0 24 Dec 18 20:46 pub
226 Directory send OK.
ftp> cd pub
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,88,128,102,108).
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 23 Dec 18 20:41 readme.txt
226 Directory send OK.
ftp> get readme.txt /tmp/readme.txt
local: /tmp/readme.txt remote: readme.txt
227 Entering Passive Mode (192,168,88,128,160,11).
150 Opening BINARY mode data connection for readme.txt (23 bytes).
226 Transfer complete.
23 bytes received in 9.7e-05 secs (237.11 Kbytes/sec)
ftp> put /tmp/example.txt /pub/example.txt
local: /tmp/example.txt remote: /pub/example.txt
227 Entering Passive Mode (192,168,88,128,209,58).
150 Ok to send data.
226 Transfer complete.
5 bytes sent in 0.000344 secs (14.53 Kbytes/sec)
ftp> ls
227 Entering Passive Mode (192,168,88,128,67,163).
150 Here comes the directory listing.
-rw-r--r-- 1 1001 50 5 Dec 18 20:50 example.txt
-rw-r--r-- 1 0 0 23 Dec 18 20:41 readme.txt
226 Directory send OK.
ftp> quit
221 Goodbye.
至此,基本的vsftpd服務的配置已經完成!