FTP(檔案傳輸協定, File Transfer Protocol)顧名思義,是專門用來傳輸檔案的通訊協定,並且這個檔案傳輸的方向是雙向的,換句話說,FTP伺服器可以提供檔案給客戶端,客戶端也可以上傳檔案到FTP伺服器上。vsftpd、pureftpd、proftpd都是在Linux作業系統上很流行的FTP伺服器軟體,其中的vsftpd最輕巧,並以安全和效能為重。



安裝vsftpd

要在Ubuntu Server上安裝vsftpd,可以直接在終端機中執行以下指令:

sudo apt install vsftpd

ubuntu-server-vsftpd

vsftpd監聽的TCP連接埠為FTP預設的21,可以使用以下指令來查看vsftpd是否有確實安裝成功。

sudo ss -tlnp | grep vsftpd

ss指令可以顯示出Socket相關的資訊。-l參數可以只顯示正在監聽中的連線。若使用ss指令時都沒給任何參數的話,會忽略掉監聽中的連線。-t參數可以只顯示TCP連線。-n參數可以讓連接埠數字直接被輸出,而不是用一個名稱代替。-p參數可以顯示佔用連線的行程。

ubuntu-server-vsftpd

如上圖,如果有看到TCP有在監聽連接埠21,就表示vsftpd安裝成功了!這個連接埠21是開在IPv6,但它也可以處理IPv4的連線。

FTP連線的主動模式和被動模式

FTP連線時有主動模式和被動模式。這兩種模式都會建立出兩個TCP連線,原先FTP伺服器開啟的連接埠21,在這兩種模式下都是用來接收客戶端發送查詢檔名、建立目錄、下載檔案、上傳檔案等等的FTP命令用的。

主動模式(Active Mode)

在主動模式下,客戶端與FTP伺服器的連接埠21進行連線後,會尋找一個可用的TCP連接埠並實施監聽。接著客戶端會再透過FTP伺服器的連接埠21,傳送夾帶了IP位址和連接埠資訊的PORT命令給FTP伺服器,用以告知FTP伺服器客戶端自己另外開啟了哪個連接埠。FTP伺服器就會根據從客戶端發送的IP位址和連接埠訊息「主動」去與客戶端再建立出一個新的連線,這個連線便會被用來進行資料的傳輸,且這個連線在FTP伺服器上的連接埠預設會是20。

一般來說,伺服器會設定防火牆,限制只接受從哪幾個連接埠進入的連線,而不會去限定伺服器主動發出的連線一定要透過哪幾個連接埠,所以伺服器端在這個模式下並不太會出現什麼問題。但對於客戶端來說,客戶端提供給FTP伺服器的IP位址必須要真的能夠被連入,像是客戶端若是經由NAT(Network Address Translation)來連上網路,在沒有特別的設定下,外部的設備均無法由客戶端提供的IP位址來連到客戶端。再加上客戶端的網路環境可能也會有防火牆存在,會把來自FTP伺服器的連線請求阻擋掉,這也是需要再另外設定的。

綜上所述,由於主動模式需要客戶端進行額外的設定,偏偏客戶端的操作者通常是不懂網路或是無權操作網路設定的一般百姓。因此FTP站若是開放給大眾使用,其實並不常用主動模式來連線。

被動模式(Passive Mode)

在被動模式下,客戶端與FTP伺服器的連接埠21進行連線後,客戶端會再透過FTP伺服器的連接埠21,傳送PASV命令給FTP伺服器。FTP伺服器會尋找一個可用的TCP連接埠並實施監聽,然後會再透過連接埠21將新開的連接埠回應給客戶端,客戶端便可以利用這個連接埠再與FTP伺服器建立另外的新連線,而這個新連線會被用來進行資料的傳輸。

在被動模式下,伺服器端的防火牆就需要去設定允許FTP資料連線用的連接埠可以被連入,而客戶端則通常不需要做任何設定就可以與FTP伺服器建立完整的FTP連線。因此FTP站若是開放給大眾使用,經常會用被動模式來連線。

然而,由於FTP伺服器在每次連接埠21建立新連線後,都需要去開啟其它可用的TCP連接埠並實施監聽,當可用的TCP連接埠被用完,就無法再建立新的FTP連線了。

FTP實際的連線方式

許多FTP客戶端會同時嘗試使用兩種連線模式來建立FTP連線。

一開始客戶端與FTP伺服器的連接埠21進行連線後,會尋找一個可用的TCP連接埠並實施監聽,接著傳送PORT命令給FTP伺服器。如果FTP伺服器成功與客戶端建立新的資料連線了,就繼續使用主動模式;如果FTP伺服器無法成功與客戶端建立新連線,客戶端就會再傳送PASV命令給FTP伺服器,使用被動模式進行連線。

設定vsftpd

vsftpd的主設定檔為/etc/vsftpd.conf。它預設的模樣長成這樣:

ubuntu-server-vsftpd

其中最重要的設定項目為listenlisten_ipv6,分別對應著監聽IPv4還是IPv6(監聽任意網路介面的話也能處理IPv4的連線),它們可以控制vsftpd的啟動方式,看是要用持續啟動的「獨立運行(standalone)」(設為YES),還是要在需要時(on demand)才由「超級服務(super daemon)」來啟動(設為NO)。

如果主機是以跑FTP服務為主,那就將listenlisten_ipv6設為YES,反應會比較快;如果不是的話,將listenlisten_ipv6設為NO,可以節省記憶體,當然我們還需要另外設定超級服務來觸發vsftpd的啟動。預設值是listen = NOlisten_ipv6 = YES。也就是說,vsftpd預設是以獨立運行的方式啟動的。

若vsftpd是以獨立運行的方式來啟動,則還可以用listen_addresslisten_address6項目來設定要監聽的網路介面的IP位址。要特別注意的是,listenlisten_ipv6項目不能夠同時是YES。如果要分別監聽不同的IPv4和IPv6的網路介面,則要用不同的設定同時啟動兩個vsftpd,而這個部份就不在本篇文章的探討範圍內了。其實將listen_address6設為YES再用防火牆來擋連線會比較省事。

若vsftpd不主動監聽TCP連接埠,而是靠超級服務來啟動,設定起來會比較複雜一點。在下面這一個獨立的小節來探討。

以超級服務(xinetd為例)來啟動vsftpd

若您想要讓vsftpd以獨立運行方式來啟動,請略過這個小節。

常用的超級服務為xinetd(Extended Internet Service Daemon),Ubuntu Server預設並沒有安裝xinetd。

安裝xinetd

要在Ubuntu Server上安裝xinetd,可以直接在終端機中執行以下指令:

sudo apt install xinetd

ubuntu-server-vsftpd

設定xinetd

xinetd的設定檔位於/etc/xinetd.d目錄中,通常一個檔案用來設定一個服務。我們可以在這個目錄底下建立vsftpd檔案,並將檔案內容填寫如下:

service ftp
{
    server                  = /usr/sbin/vsftpd
    socket_type             = stream
    wait                    = no
    user                    = root
    nice                    = 10
    instances               = 64
    per_source              = 7
    disable                 = no
  # bind                    = 192.168.0.1
}

以上設定中service ftpftp必須要存在於/etc/services檔案中,預設是21/tcp。也就是說,xinetd會去監聽TCP連接埠21的連線,並用上面的設定來處理這個連線。

server項目用來設定xinetd接到連線之後,要把這個連線交給哪個程式(路徑)進行處理。/usr/sbin/vsftpd即為vsftpd的執行檔路徑。

socket_type項目是指xinetd與server項目設定的程式建立的Socket類型。streamSOCK_STREAM,會建立穩定的TCP連線。

wait項目設定xinetd是否需等到上次連線處理完之後,再去執行server項目設定的程式。

user項設定執行server項目設定的程式的行程屬於哪個使用者。如果沒有設定group項目的話,group項目的值會和user項目一樣。

nice項目設定執行server項目設定的程式的行程的nice值。既然都已經是透過超級服務來執行vsftpd,通常我們也不希望vsftpd的優先權太高而影響到其它重要的服務,所以會設定高一點的nice值。

instances項目設定最多同時處理幾組FTP連線。per_source項目設定同一IP最多同時允許幾組FTP連線,其實也就影響著同一個IP最多可以上傳和下載幾個檔案啦!

disable項目設為no表示要啟用這個service區塊設定;設為yes表示要禁用這個service區塊設定。

bind項目可以設定這個service區塊要監聽來自哪個網路介面IP位址的連線。如果不設定就是任意的網路介面。前面加井字號#是要註解掉這行設定。

套用xinetd的新設定

執行以下指令就可以重新載入xinetd的設定檔:

sudo systemctl reload xinetd

ubuntu-server-vsftpd

執行以下指令檢查xinetd是否有在監聽TCP連接埠21:

sudo ss -tlnp | grep xinetd

ubuntu-server-vsftpd

如上圖,如果有看到TCP有在監聽連接埠21,就表示xinetd設定成功了!這個連接埠21是開在IPv6,但它也可以處理IPv4的連線。

vsftpd的其它設定項目

回到vsftpd的主設定檔/etc/vsftpd.conf。其它比較重要的設定項目有以下幾個:

  • use_localtime:設定是否使用FTP伺服器設定的時區來顯示時間。預設是YES
  • connect_from_port_20:設定是否固定使用連接埠20作為主動模式連到客戶端時使用的連接埠。預設是YES
  • write_enable:設定是否允許本地端的Linux使用者(一般使用者)更動(新增、修改、刪除)FTP伺服器上的檔案。不設定的話表示不允許。
  • local_umask:設定一般使用者的umask。不設定的話同077。也就是說建立檔案時的檔案權限會是600(666 - 077),建立目錄時的檔案權限會是700(777 - 077)。
  • user_sub_token:指定一個代表使用者名稱的「記號」(token)。
  • local_root:修改一般使用者登入後最先進入的目錄路徑。不設定或是設定的目錄不存在的話會進入家目錄。目錄路徑中可以包含user_sub_token項目所設定的token,假設這個token是設為$USER,而目錄路徑設為/home/$USER/ftp,表示使用者登入後要立即進入家目錄下的ftp目錄中
  • chroot_local_userchroot_list_enable:修改一般使用者透過FTP登入後所能到達的根目錄。不設定的話表示不修改,也就是以Linux作業系統的/作為根目錄。本篇文章後面會再介紹這幾個項目的設定方式。
  • anonymous_enable:設定是否允許匿名登入。也就是不需帳號密碼就可以登入FTP站台。預設是NO,不允許。若想直接透過FTP網址來提供檔案給別人的話,就要允許這個項目。
  • anon_root:設定匿名使用者的根目錄。不設定就無法讓匿名使用者存取檔案。要注意的是,任何使用者(包括一般使用者和匿名使用者)對其根目錄都不能有寫入權限,所以作為匿名使用者根目錄的目錄,其others不能加上寫入權限。若匿名使用者需要上傳檔案,就只能上傳檔到有對others開啟寫入權限的子目錄中,不能直接傳到根目錄。
  • anon_umask:設定匿名使用者的umask。不設定的話同077
  • anon_upload_enable:設定匿名使用者是否也可以跟著一般使用者擁有上傳檔案的權限。不設定的話表示不允許。
  • anon_mkdir_write_enable:設定匿名使用者是否也可以跟著一般使用者擁有建立目錄的權限。不設定的話表示不允許。
  • anon_other_write_enable:設定匿名使用者是否也可以跟著一般使用者擁有除了上傳檔案和建立目錄之外的其它修改權限。不設定的話表示不允許。
  • anon_max_rate:限制全部匿名使用者的總連線速度(位元組/秒)。不設定的話表示不限制。
  • chown_uploadschown_username:設定匿名使用者上傳檔案後,要自動將檔案的擁有者改為哪個真實存在的使用者。不設定的話表示不修改,就會用ftp作為擁有者和群組。
  • local_enable:設定是否允許使用一般使用者帳號登入FTP站台。預設是YES,允許。如果將這個項目設為NO,那麼就只可以允許使用匿名使用者來登入FTP站台。
  • pasv_enable:設定是否允許被動模式。不設定的話表示允許。
  • pasv_min_portpasv_max_port:設定被動模式時,監聽資料連線可用的連接埠範圍。不設定的話表示沒有範圍限制。
  • accept_timeout:設定建立被動連線模式時的逾時時間(秒)。不設定的話當作60。建議將這個值設為小於60的值,避免伺服器的連接埠被長時間佔用。
  • connect_timeout:設定建立主動連線模式時的逾時時間(秒)。不設定的話當作60
  • idle_session_timeout:設定客戶端多久(秒)沒發送命令就斷開與FTP伺服器連接埠21的連線(資料連線還是會保留)。不設定的話當作300
  • data_connection_timeout:設定資料連線的逾時時間。不設定的話當作300
  • hide_ids:設定是某隱藏檔案的擁有者和群組。不設定的話當作NO。若設為YES,會將擁有者和群組以ftp來顯示。
  • pam_service_name:設定要使用哪個PAM服務來驗證使用者。預設是vsftpd。若沒有這個服務,就會使用Linux作業系統的使用者作為FTP的一般使用者。這個部份會和虛擬使用者登入有關,會在文章後面做介紹。

若vsftpd是以獨立運行的方式來啟動,還可以用以下的設定項目進行連線數量的限制:

  • max_clients:設定最多同時處理幾組FTP連線。不設定的話表示沒有限制。
  • max_per_ip:設定同一IP最多同時允許幾組FTP連線,其實也就影響著同一個IP最多可以上傳和下載幾個檔案啦!不設定的話表示沒有限制。

chroot的設定

「chroot」為「change root directory」,可以讓使用者無法觸及到比根目錄還要更上層的檔案。

chroot_local_user

chroot_local_user項目設為YES,可以將一般使用者的根目錄都設定為他們各自的家目錄。要注意的是,任何使用者(包括一般使用者和匿名使用者)對其根目錄都不能有寫入權限,所以還需要用以下設定調整所有一般使用者家目錄的權限。

sudo chmod u-w /home/*

所以要讓一般使用者透過FTP上傳檔案的話,只能夠在使用者家目錄中事先新增能讓該使用者寫入的子目錄才行。

chroot_list_enable

相較於chroot_local_user設定項目是直接去修改「所有」一般使用者的根目錄為他們各自的家目錄,chroot_list_enable項目則可以修改「指定某幾個」一般使用者的根目錄為他們各自的家目錄。指定的方式是透過一個獨立的chroot清單檔案,預設路徑為/etc/vsftpd.chroot_list,可能需自行建立。

chroot清單檔案的撰寫方式如下:

user1,user2,user3

以上的chroot清單檔案,在chroot_list_enable = YESchroot_local_user不是YES時,user1user2user3使用者的根目錄會被設定為他們自己的家目錄。若chroot_list_enable = YESchroot_local_user = YES時,則除了user1user2user3使用者以外,其它一般使用者的根目錄會被設定為他們自己的家目錄。

當然,用chroot_list_enable項目去修改使用者根目錄,也是要去注意根目錄的寫入權限,不能讓使用者自己擁有該目錄的寫入權限。

另外還有chroot_list_file設定項目,可以修改chroot清單檔案的路徑。

虛擬使用者(Virtual User)

上面介紹的FTP登入方式共有實體使用者(Linux作業系統的使用者,即上面一直提到的一般使用者)和匿名使用者兩種,如果有特殊需求需要允許非Linux作業系統使用者的使用者也能夠實名登入FTP站台的話,那麼可以使用這小節介紹的方式來設定虛擬使用者。不過用了這個方式後,就不能再用原先的實體使用者來登入FTP站台了。

這個方式需要用到PAM(Linux Pluggable Authentication Modules),PAM的設定檔位於/etc/pam.d目錄中,設定檔的格式如下:

服務名稱 類型 驗證後要做的事 模組路徑 模組參數

其中,類型有以下幾種:

  • account:提供帳號檢驗。像是使用者的密碼是否過期,使用者是否有被允許存取某項服務等。
  • auth:提供使用者身份驗證。像是要求使用者輸入密碼,或是使用視網膜、指紋辨識週邊設備來驗證身份。
  • password:提供使用者身分驗證的修訂功能。像是修改密碼。
  • session:記錄使用者登入後到登出前的資訊。

驗證後要做的事有以下幾種:

  • requisite:驗證失敗的話立刻回報。
  • required:驗證失敗的話不立刻回報,會在其它模組都調用完畢後才回報。
  • sufficient:驗證成功的話立刻回報。
  • optional:只有在這個服務和類型僅使用一個模組時,驗證有無成功才是重要的。這個通常是拿來顯示訊息用的。

我們可以在/etc/pam.d目錄中建立一個vsftpd設定檔,檔案內容如下:

auth       required     pam_userdb.so db=/etc/vsftpd.vusers
account    required     pam_userdb.so db=/etc/vsftpd.vusers
session    required     pam_loginuid.so

上面的設定並沒有包含服務名稱,服務名稱即為設定檔檔名vsftpd。這個PAM服務要使用/etc/vsftpd.vusers.db檔案作為使用者帳密和身份驗證的資料庫,並且把登入識別碼記錄起來。在使用pam_userdb.so的時候,檔案路徑不必加上.db,它會自動加,不能自己加上。至於/etc/vsftpd.vusers.db檔案是什麼,要怎麼產生,等等會介紹。先再執行以下指令來安裝db-util套件吧!

sudo apt install db-util

ubuntu-server-vsftpd

然後用以下的方式設定vsftpd的主設定檔:

local_enable=YES
guest_enable=YES
virtual_use_local_privs=YES
chroot_local_user=YES
user_sub_token=$USER
local_root=/home/vftp/$USER

上面有幾個是先前沒有介紹過的設定項目,如下:

  • guest_enable:設定是否將一般使用者作為「訪客」,寄宿到某個使用者(以guest_username項目來設定,預設是ftp)下。不設定的話表是否。換句話說,可以讓登入至FTP站台的一般使用者通通都當作是某個指定的使用者,方便進行權限的控管。
  • virtual_use_local_privs:設定透過PAM驗證的虛擬使用者是否擁有一般使用者的權限。不設定的話就是只有匿名使用者的權限。

建立存放虛擬使用者家目錄的目錄/home/vftp。可以使用以下指令:

sudo mkdir /home/vftp && sudo chown ftp:ftp /home/vftp

後面的chown指令其實並非必要,只是我們習慣把家目錄的擁有者和群組設為套用該家目錄的使用者以及其專屬群組。

ubuntu-server-vsftpd

用以下指令來建立虛擬使用者清單檔案,路徑可以放在/etc/vsftpd.vusers

sudo touch /etc/vsftpd.vusers && sudo chmod 600 /etc/vsftpd.vusers

因為這個檔案會包含密碼,所以只讓root帳號有權限讀寫。

ubuntu-server-vsftpd

編輯虛擬使用者並產生使用者資料庫

編輯虛擬使用者清單檔案/etc/vsftpd.vusers,單數行為使用者的帳號,雙數行為使用者的密碼,一組使用者帳號密碼會佔用連續的兩行。檔案內容的結構如下:

user1
password1
user2
password2
user3
password3

以上設定,第1組使用者的帳號為user1,密碼為password1,依此類推。

接著用以下指令來產生資料庫:

sudo db_load -T -t hash -f /etc/vsftpd.vusers /etc/vsftpd.vusers.db && sudo chmod 600 /etc/vsftpd.vusers.db

ubuntu-server-vsftpd

產生出來的資料庫檔案權限當然也是只讓root帳號有權限讀寫。

若有新增虛擬使用者,要使用mkdir指令新增虛擬使用者的家目錄。例如:

sudo mkdir /home/vftp/user1

在SSL/TLS通道上建立FTP連線

由於FTP是採用未加密的明碼傳輸,因此在傳輸過程中若有遭有心人士擷取封包,很容易導致帳號密碼以及檔案文件外洩。如果要在網際網路中使用FTP,最好還是把FTP連線建立在SSL/TLS通道上,使其變成俗稱的FTPS。

首先執行以下指令產生自我簽署的SSL憑證。

sudo make-ssl-cert generate-default-snakeoil --force-overwrite

ubuntu-server-vsftpd

私鑰會被放在/etc/ssl/private/ssl-cert-snakeoil.key,證書會被放在/etc/ssl/certs/ssl-cert-snakeoil.pem,有效期為10年。

如果您有大略瀏覽過vsftpd的主設定檔,會發現裡面已經有設定好rsa_cert_file項目和rsa_private_key_file項目了。我們要做的只是把ssl_enable項目設為YES即可啟用SSL/TLS通道。

另外,關於FTPS,還有以下幾個常用的設定項目可以調整:

  • allow_anon_ssl:是否允許匿名使用者使用SSL/TLS通道。不設定的話是不允許。如果FTP站台只是提供給匿名使用者下載檔案的話,建議不要允許,節省系統資源。但如果匿名使用者可以上傳檔案的話,還是允許一下會比較好。
  • force_anon_data_ssl:是否強制讓匿名使用者使用SSL/TLS通道建立資料連線。不設定的話是不強制。設定策略同allow_anon_ssl項目。allow_anon_ssl項目必須要啟用才可以啟用這個項目。如果啟用這個項目,就不能直接給人FTP網址下載檔案。
  • force_local_data_ssl:是否強制讓一般使用者使用SSL/TLS通道建立資料連線。不設定的話是不強制。建議設為YES,強制使用。
  • force_local_logins_ssl:是否強制讓一般使用者使用SSL/TLS通道進行登入(傳遞密碼)。不設定的話是YES。建議設為YES,強制使用。

套用vsftpd的新設定

若vsftpd是以獨立運行的方式來啟動,執行以下指令來重啟vsftpd:

sudo systemctl restart vsftpd

ubuntu-server-vsftpd

若vsftpd是透過超級服務來啟動,在設定檔修改之後建立的FTP連線都會套用到新的設定。