FTP使用2个TCP端口,首先是建立一个命令端口(控制端口),然后再产生一个数据端口。ftp工作在主动模式使用tcp 21 和 20 两个端口,而工作在被动模式会工作在大于1024随机端口。
主动模式(port):
主动方式的FTP是这样的:客户端从一个任意的非特权端口N(N>1024)连接到FTP服务器的命令端口,即tcp 21端口。紧接着客户端开始监听端口N+1,并发送FTP命令“port N+1”到FTP服务器。最后服务器会从它自己的数据端口(20)连接到客户端指定的数据端口(N+1),这样客户端就可以和ftp服务器建立数据传输通道了。
针对FTP服务器的防火墙来说,必须允许以下通讯才能支持主动方式FTP:4、客户端>1024端口到FTP服务器的20端口(入:客户端发送ACK响应到服务器的数据端口 S<-C)
被动模式(pasv):
在被动方式FTP中,命令连接和数据连接都由客户端。当开启一个FTP连接时,客户端打开两个任意的非特权本地端口(N >1024和N+1)。第一个端口连接服务器的21端口,但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连它的数据端口,而是提交 PASV命令。这样做的结果是服务器会开启一个任意的非特权端口(P >1024),并发送PORT P命令给客户端。然后客户端发起从本地端口N+1到服务器的端口P的连接用来传送数据。
对于服务器端的防火墙来说,必须允许下面的通讯才能支持被动方式的FTP:4、服务器的大于1024端口到远程的大于1024的端口(出:服务器发送ACK响应和数据到客户端的数据端口 S->C)
状态码:
1XX:信息 125:数据连接打开
2XX:成功类状态 200:命令OK 230:登录成功
3XX:补充类 331:用户名OK
4XX:客户端错误 425:不能打开数据连接
5XX:服务器错误 530:不能登录
用户认证:
匿名用户:ftp,anonymous,对应Linux用户ftp
系统用户:Linux用户,用户/etc/passwd,密码/etc/shadow
虚拟用户:特定服务的专用用户,独立的用户/密码文件
使用 vsftpd 提供 ftp 服务。
[root@CentOS74 ~]# yum install vsftpd
匿名用户(映射为系统用户ftp )共享文件位置:/var/ftp
系统用户共享文件位置:用户家目录
虚拟用户共享文件位置:为其映射的系统用户的家目录
修改 vsftpd 配置,配置文件存放在 /etc/vsftpd/vsftpd.conf
服务配置
命令端口:listen_port=21
主动模式端口:ftp_data_port=20
被动模式端口范围:pasv_min_port=6000 pasv_max_port=6010(0为随机分配)
linux客户端默认使用被动模式,windows 客户端默认使用主动模式。
使用当地时间:use_localtime=YES(默认为NO,使用GMT)
启用记录上传下载日志:xferlog_enable=YES
记录wu-ftp格式日志:xferlog_std_format=YES
日志文件存放路径:xferlog_file=/var/log/xferlog
记录vsftpd格式日志:dual_log_enable=YES
日志文件存放路径:vsftpd_log_file=/var/log/vsftpd.log
登录提示信息:ftpd_banner=“welcome to mage ftp server"(高优先级)
登录提示信息文件:banner_file=/etc/vsftpd/ftpbanner.txt
目录访问提示信息:dirmessage_enable=YES
目录访问提示信息存放文件:message_file=.message(在对应文件夹里)
匿名用户配置
支持匿名用户:anonymous_enable=YES
匿名用户略过口令检查:no_anon_password=YES
只能下载权限比444大的文件:anon_world_readable_only=YES
匿名上传文件:anon_upload_enable=YES
匿名上传目录:anon_mkdir_write_enable=YES
可删除和修改上传的文件:anon_other_write_enable=YES
ftp> put anaconda-ks.cfg #当开启匿名上传后,发现还是无法上传文件
local: anaconda-ks.cfg remote: anaconda-ks.cfg
227 Entering Passive Mode (192,168,30,74,176,212).
550 Permission denied. #权限被拒绝,原因是目标文件夹对ftp用户没有写权限
[root@CentOS74 ftp]# setfacl -m u:ftp:rwx /var/ftp/pub/ #对ftp用户通过acl授权
[root@CentOS74 ftp]# getfacl /var/ftp/pub/
getfacl: Removing leading '/' from absolute path names
# file: var/ftp/pub/
# owner: root
# group: root
user::rwx
user:ftp:rwx #ftp用户对目录/var/ftp/pub/拥有读写执行权限
group::r-x
mask::rwx
other::r-x
ftp> put anaconda-ks.cfg #上传文件
local: anaconda-ks.cfg remote: anaconda-ks.cfg
227 Entering Passive Mode (192,168,30,74,194,80).
150 Ok to send data.
226 Transfer complete.
1433 bytes sent in 0.000365 secs (3926.03 Kbytes/sec)
ftp> ls
227 Entering Passive Mode (192,168,30,74,88,235).
150 Here comes the directory listing.
-rw------- 1 14 50 1433 Jun 26 12:19 anaconda-ks.cfg
226 Directory send OK.
指定匿名上传文件的umask:anon_umask=077
上传文件时更改所有者:chown_uploads=YES
指定上传文件默认的所有者:chown_username=jiangbowen
指定上传文件默认的权限:chown_upload_mode=0644
[root@CentOS74 pub]# ll
total 4
-rw------- 1 ftp ftp 1433 Jun 26 20:19 anaconda-ks.cfg
ftp> put test
local: test remote: test
227 Entering Passive Mode (192,168,30,74,113,195).
150 Ok to send data.
226 Transfer complete.
[root@CentOS74 pub]# ll
total 0
-rw-r--r-- 1 jiangbowen ftp 0 Jun 26 20:36 test #所有者和权限修改为配置文件中的定义
系统用户配置
所有系统用户都映射成guest用户:guest_enable=YES
指定guest用户:guest_username=ftpuser
[root@CentOS74 pub]# useradd -d /data/ftp ftpuser
[root@CentOS74 pub]# chmod 555 /data/ftp/ #根目录不能有写权限,同时又要访问根目录,所以要将权限设置为555
[root@CentOS74 pub]# ll /data/ftp/ -d
dr-xr-xr-x 2 ftpuser ftpuser 74 Jun 26 21:00 /data/ftp/
ftp> ls
227 Entering Passive Mode (192,168,30,74,23,54).
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 0 Jun 26 13:00 dir1
226 Directory send OK.
ftp> pwd
257 "/" #将/data/ftp目录映射为根目录
允许linux用户登录:local_enable=YES
允许linux用户上传文件:write_enable-YES
指定系统用户上传文件的默认权限:local_umask=022
非匿名用户登录所在目录:local_root=/ftproot
[root@CentOS74 ftp]# mkdir /data/ftproot
[root@CentOS74 ftp]# chmod 555 /data/ftproot/
[root@CentOS74 ftp]# touch /data/ftproot/roottest
ftp> pwd
257 "/"
ftp> ls
227 Entering Passive Mode (192,168,30,74,64,235).
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 0 Jun 26 13:09 roottest #根目录为/data/ftproot/
226 Directory send OK.
禁锢系统用户:chroot_local_user=YES
Name (192.168.30.74:root): jiangbowen
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 #jiangbowen用户的家目录有写权限,没有家目录也会登陆失败
禁锢(或不禁锢)列表中的系统用户:chroot_list_enable=YES(NO)
指定禁锢用户列表:chroot_list_file=/etc/vsftpd/chroot_list
登陆与连接配置
使用pam模块完成用户认证:pam_service_name=vsftpd
查看 vsftpd 模块的配置文件 /etc/pam.d/vsftpd
[root@CentOS74 ftp]# cat /etc/pam.d/vsftpd
#%PAM-1.0
session optional pam_keyinit.so force revoke
auth required pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed
auth required pam_shells.so ^拒绝指定文件中存放的用户登陆
auth include password-auth
account include password-auth
session required pam_loginuid.so
session include password-auth
查看 /etc/vsftpd/ftpusers 文件中的用户
[root@CentOS74 ftp]# cat /etc/vsftpd/ftpusers
# Users that are not allowed to login via ftp
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
news
uucp
operator
games
nobody
启用控制用户登录的列表文件:userlist_enable=YES
userlist 为黑名单:userlist_deny=YES(NO为白名单)
用户列表的存放的路径:userlist_file=/etc/vsftpd/users_list
[root@CentOS74 pam.d]# cat /etc/vsftpd/user_list
# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
# If userlist_deny=YES (default), never allow users in this file, and
# do not even prompt for a password.
# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
# for users that are denied.
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
news
uucp
operator
games
nobody
使用 root 用户登陆 ftp
Name (192.168.30.74:root): root
530 Permission denied.
Login failed. #登陆失败
最大并发连接数:max_clients=0
每个IP同时发起的最大连接数:max_per_ip=0(0为不限制)
vsftpd服务指定用户身份运行:nopriv_user=nobody
[root@CentOS74 pam.d]# ps aux | grep ftp
root 11920 0.0 0.0 53212 576 ? Ss 22:27 0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
root 11931 0.0 0.0 55336 1336 ? Ss 22:30 0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
jiangbo+ 11932 0.0 0.0 55348 848 ? S 22:30 0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf #以指定用户身份运行
匿名用户的最大传输速率:anon_max_rate=0(0为不限制)
系统用户的最大传输速率:local_max_rate=0
主动模式数据连接超时时长:connect_timeout=60
被动模式数据连接超时时长:accept_timeout=60
数据连接无数据输超时时长:data_connection_timeout=300
无命令操作超时时长:idle_session_timeout=60
以文本方式上传数据:ascii_upload_enable=YES(默认二进制)
以文本方式下载数据:ascii_download_enable=YES
UNIX系列系统默认使用二进制传输数据,DOS系列系统默认使用文本传输数据。
(1)创建自签名证书
使用 make 脚本自动创建
[root@CentOS74 ~]# cd /etc/pki/tls/certs/
[root@CentOS74 certs]# make vsftpd.pem
umask 77 ; \
PEM1=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
PEM2=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
/usr/bin/openssl req -utf8 -newkey rsa:2048 -keyout $PEM1 -nodes -x509 -days 365 -out $PEM2 ; \
cat $PEM1 > vsftpd.pem ; \
echo "" >> vsftpd.pem ; \
cat $PEM2 >> vsftpd.pem ; \
rm -f $PEM1 $PEM2
Generating a 2048 bit RSA private key
..........................................................................................+++
...................+++
writing new private key to '/tmp/openssl.21EOKs'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:henan
Locality Name (eg, city) [Default City]:zhengzhou
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:jiangbowen
Email Address []:
或者使用 openssl 命令手动创建自签名证书,创建完证书后将证书内容追加至自签证书内
[root@CentOS74 CA]# (umask 066; openssl genrsa -out /etc/pki/CA/private/cakey.pem 2048)
Generating RSA private key, 2048 bit long modulus
.......................+++
......................................+++
e is 65537 (0x10001)
[root@CentOS74 CA]# openssl req -new -x509 -key /etc/pki/CA/private/ftpkey.pem -days 7300 -out /etc/pki/CA/cacert.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:HeNan
Locality Name (eg, city) [Default City]:ZhengZhou
Organization Name (eg, company) [Default Company Ltd]:Linux
Organizational Unit Name (eg, section) []:CentOS
Common Name (eg, your name or your server's hostname) []:jiangbowen
Email Address []:
(2)配置 vsftpd 服务支持 SSL
[root@CentOS74 vsftpd]# cat /etc/vsftpd/vsftpd.conf | grep ssl
ssl_enable=YES #启用SSL
allow_anon_ssl=NO #匿名不支持SSL
force_local_logins_ssl=YES #本地用户登录加密
force_local_data_ssl=YES #本地用户数据传输加密
rsa_cert_file=/etc/pki/tls/certs/vsftpd.pem #证书文件存放路径
(3)使用 filezilla 登陆 ftp 服务器,linux系统中 ftp 工具不支持加密传输
所有虚拟用户会统一映射为一个指定的系统帐号:访问共享位置,即为此系统帐号的家目录。各虚拟用户可被赋予不同的访问权限,通过匿名用户的权限控制参数进行指定。
基于文件验证
(1)创建用户数据库文件
[root@CentOS74 vsftpd]# cat /etc/vsftpd/vusers.txt #创建用户文本,用户密码成对出现
jiangbowen
123456
ftpuser
123456
nohome
123456
[root@CentOS74 vsftpd]# db_load -T -t hash -f vusers.txt vusers.db #使用db_load生成用户数据库文件
[root@CentOS74 vsftpd]# chmod 600 vusers.db #更改数据库文件权限
[root@CentOS74 vsftpd]# ll vusers.db
-rw------- 1 root root 12288 Jun 28 05:27 vusers.db
(2)创建用户和访问 FTP 目录
[root@CentOS74 vsftpd]# useradd -d /var/ftproot -s /sbin/nologin vuser #创建本地映射用户
[root@CentOS74 vsftpd]# chmod 555 /var/ftproot/ #修改映射用户及目录权限,去掉写权限
[root@CentOS74 vsftpd]# ll -d /var/ftproot/
dr-xr-xr-x 2 vuser vuser 62 Jun 28 05:31 /var/ftproot/
[root@CentOS74 vsftpd]# mkdir /var/ftproot/testdir #创建文件夹,用于上传文件
[root@CentOS74 vsftpd]# setfacl -m u:vuser:rwx /var/ftproot/testdir #赋予映射用户读写执行的ACL权限
[root@CentOS74 vsftpd]# ll /var/ftproot/
total 0
drwxrwxr-x+ 2 root root 6 Jun 28 05:32 testdir
(3)创建 pam 配置文件,并启用 pam 模块
[root@CentOS74 ~]# cat /etc/pam.d/vsftpd.db #创建pam模块配置文件
auth required pam_userdb.so db=/etc/vsftpd/vusers #根据用户数据库,使用pam_userdb模块
account required pam_userdb.so db=/etc/vsftpd/vusers #控制登陆
[root@CentOS74 ~]# cat /etc/vsftpd/vsftpd.conf | grep pam
pam_service_name=vsftpd.db #启用vsftpd.db
[root@CentOS74 ~]# cat /etc/vsftpd/vsftpd.conf | grep guest
guest_enable=YES #启用虚拟用户
guest_username=vuser #指定虚拟用户
(4)创建远程用户的独立配置文件
[root@CentOS74 ~]# cat /etc/vsftpd/vsftpd.conf | grep user_config
user_config_dir=/etc/vsftpd/vusers.d/
[root@CentOS74 ~]# mkdir /etc/vsftpd/vusers.d/
创建用户的配置文件,使其可读可写
[root@CentOS74 ~]# cat /etc/vsftpd/vusers.d/jiangbowen
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES
创建用户的配置文件,修改其登陆目录
[root@CentOS74 ~]# cat /etc/vsftpd/vusers.d/nohome
local_root=/var/nohome #更改用户的登陆目录
[root@CentOS74 ~]# mkdir /var/nohome #创建对应的目录
[root@CentOS74 ~]# setfacl -m u:vuser:rwx /var/nohome/ #赋予虚拟用户权限
不创建用户配置文件的话,其权限根据主配置文件中对虚拟用户的定义
测试三个用户登陆 ftp 服务器的情况
Name (192.168.30.74:root): jiangbowen #拥有读写权限
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd testdir
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,30,74,252,126).
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 0 Jun 27 22:16 ftproot.mark
226 Directory send OK.
ftp> put anaconda-ks.cfg
local: anaconda-ks.cfg remote: anaconda-ks.cfg
227 Entering Passive Mode (192,168,30,74,218,239).
150 Ok to send data. #可以上传文件,并新建目录
226 Transfer complete.
1433 bytes sent in 0.0102 secs (140.56 Kbytes/sec)
ftp> ls
227 Entering Passive Mode (192,168,30,74,211,178).
150 Here comes the directory listing.
-rw------- 1 1003 1003 1433 Jun 27 22:19 anaconda-ks.cfg
-rw-r--r-- 1 0 0 0 Jun 27 22:16 ftproot.mark
226 Directory send OK.
Name (192.168.30.74:root): ftpuser #没有单股设置权限,使用默认配置
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd testdir
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,30,74,206,144).
150 Here comes the directory listing.
-rw------- 1 1003 1003 1433 Jun 27 22:19 anaconda-ks.cfg
-rw-r--r-- 1 0 0 0 Jun 27 22:16 ftproot.mark
226 Directory send OK.
ftp> put test
local: test remote: test
227 Entering Passive Mode (192,168,30,74,215,168).
550 Permission denied. #无法上传文件,权限被拒绝
Name (192.168.30.74:root): nohome #更改登陆目录
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,30,74,96,172).
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 0 Jun 27 22:17 nohome.mark #成功更改登陆目录
226 Directory send OK.
基于MySql验证
(1)安装必要组件 mariadb 服务器、开发包,pam 模块开发包
[root@CentOS74 ~]# yum install mariadb-devel pam-devel mariadb-server.x86_64
(2)编译安装 pam_mysql 模块,源码包需要从网络上下载
[root@CentOS74 /]# ls /lib64/security/pam_mysql.so
/lib64/security/pam_mysql.so
(3)配置 MySql 数据库
创建管理用户
MariaDB [(none)]> GRANT SELECT ON ftpuser.* TO [email protected] IDENTIFIED BY 'dengniaiwo123';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
新建虚拟用户数据库和用户列表
MariaDB [(none)]> USE ftpuser;
Database changed
MariaDB [ftpuser]> CREATE TABLE ftpuserlist (id int auto_increment primary key,name char(30),passwd char(50));
Query OK, 0 rows affected (0.02 sec)
MariaDB [ftpuser]> INSERT INTO ftpuserlist(name,passwd) values('ftpuser1',password('123456')),('ftpuser2',password('123456')),('ftpuser3',password('123456'));
Query OK, 3 rows affected (0.03 sec)
Records: 3 Duplicates: 0 Warnings: 0
[root@CentOS74 /]# mysql -uftpadmin -h192.168.30.74 -pdengniaiwo123 #测试数据库连接
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 12
Server version: 5.5.56-MariaDB MariaDB Server
Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> select * from ftpuser.ftpuserlist; #查看能否查找ftpuserlist表
+----+----------+-------------------------------------------+
| id | name | passwd |
+----+----------+-------------------------------------------+
| 1 | ftpuser1 | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| 2 | ftpuser2 | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| 3 | ftpuser3 | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+----+----------+-------------------------------------------+
3 rows in set (0.00 sec)
(4)配置 vsftpd 服务
根据数据库信息创建 pam_mysql 模块的配置文件
[root@CentOS74 vsftpd]# cat /etc/pam.d/vsftpd.mysql
auth required pam_mysql.so user=ftpadmin passwd=dengniaiwo123 host=192.168.30.74 db=ftpuser table=ftpuserlist usercolumn=name passwdcolumn=passwd crypt=2
account required pam_mysql.so user=ftpadmin passwd=dengniaiwo123 host=192.168.30.74 db=ftpuser table=ftpuserlist usercolumn=name passwdcolumn=passwd crypt=2
crypt:加密方式
0表示不加密
1表示crypt(3)加密
2表示使用mysql password()函数加密
3表示md5加密
4表示sha1加密
修改主配置文件,与基于文件验证一样,只不过将 pam 模块加载为 pam_mysql 模块
[root@CentOS74 vsftpd]# cat /etc/pam.d/vsftpd.mysql
auth required pam_mysql.so user=ftpadmin passwd=dengniaiwo host=192.168.30.74 db=ftpuser table=ftpuserlist usercolumn=name passwdcolumn=passwd crypt=2
account required pam_mysql.so user=ftpadmin passwd=dengniaiwo host=192.168.30.74 db=ftpuser table=ftpuserlist usercolumn=name passwdcolumn=passwd crypt=2
[root@CentOS74 vsftpd]# cat vsftpd.conf | grep vsftpd.mysql
pam_service_name=vsftpd.mysql
测试登陆使用虚拟用户 ftp 服务器
Name (192.168.30.74:root): ftpuser1
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd testdir
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,30,74,70,62).
150 Here comes the directory listing.
-rw------- 1 1003 1003 1433 Jun 27 22:19 anaconda-ks.cfg
-rw-r--r-- 1 0 0 0 Jun 27 22:16 ftproot.mark
226 Directory send OK.