一.vsftpd简介
Vsftpd是一个基于GPL发布的类UNIX系统的ftp服务器软件.其全称是Very Secure FTP Deamon,在安全性,速度和稳定性都有着不俗的表现.在安全性方面,vsftpd针对程序的权限来设计,以一般身份启动服务,对Linux系统的使用权限较低;在千兆以太网上,vsftpd的速度可以达到86MB/s;在稳定性上更是优秀,资料表明,完全工作24小时,传输数据达2.6TB,平均并发连接为1500用户,峰值达4000用户,而这些还是在单机上实现的.此外,vsftpd 还包括以下特性:
基于IP的虚拟服务器
虚拟用户,结合数据库的用户验证
每个用户独立配置文件
速率限制
IPV6支持
支持SSL加密传输
……
以下站点一直在使用vsftpd(这仅仅是很少很少的一部分站点)
ftp.redhat.com
ftp.suse.com
ftp.debian.org
ftp.openbsd.org
ftp.freebsd.org
ftp.gnu.org
ftp.gnome.org
ftp.kde.org
ftp.kernel.org
rpmfind.net
ftp.linux.org.uk
ftp.gimp.org
ftp-stud.fht-esslingen.de
gd.tuwien.ac.at
ftp.sunet.se
ftp.ximian.com
ftp.engardelinux.org
ftp.sunsite.org.uk
ftp.isc.org
以上内容摘自vsftpd官方网站http://vsftpd.beasts.org/
二.软件安装和卸载
获得软件
vsftpd目前最新版本为2.1.0,下载地址:ftp://vsftpd.beasts.org/users/cevans/vsftpd-2.1.0.tar.gz
软件安装
# tar zxvf vsftpd-2.1.0.tar.gz
# cd vsftpd-2.1.0
# vi builddefs.h
找到下面三行,其含义如右所示
#undef VSF_BUILD_TCPWRAPPERS //是否允许使用TCP Wrappers
#define VSF_BUILD_PAM //是否允许使用PAM认证
#undef VSF_BUILD_SSL //是否允许使用SSL
如果要允许以上所示某项功能,使把undef改为define即可,注意每行前的“#“号不是注释,不能去掉.其中TCP Wrappers是一个验证IP地址合法性的程序,PAM认证让vsftpd支持本地用户登陆服务器,使用SSL可以建立一个加密的数据传输.这里我们把三项都启用.
编译安装.如果系统中安装有旧版vsftpd,请先卸载它.默认安装执行文件在/usr/local/sbin中,man page放在/usr/local/man/man5与/usr/local/man/man8中.
# make
# make install
将默认配置文件考贝到/etc/vsftpd/
# mkdir /etc/vsftpd/
# cp vsftpd.conf /etc/vsftpd/
为了认vsftpd支持本地用户登录,我们将身份认证模块文件考入系统中.
# cp RedHat/vsftpd.pam /etc/pam.d/vsftpd
建立ftp用户及主目录:
# mkdir /var/ftp
# useradd -d /var/ftp ftp
如果本来就已经存在ftp用户,则执行下面两条命令:
# chown root:root /var/ftp
# chmod 755 /var/ftp
建立vsftpd需要的特殊目录:
# mkdir /usr/share/empty/
软件卸载
如果需要卸载,使用如下命令:
# rm /usr/local/sbin/vsftpd
# rm /usr/local/man/man5/vsftpd.conf.5
# rm /usr/local/man/man8/vsftpd.8
# rm /etc/xinetd.d/vsftpd
# rm -rf /etc/vsftpd
三.配置vsftpd服务
服务的启动与停止
启动服务之前,我们先编辑配置文件/etc/vsftpd/vsftpd.conf.打开配置文件后可以看到许多以"#"开始的行,这些行都是注释行,大多是帮助信息,可以仔细阅读.vsftpd.conf文件的所有项目都是以"参数=值"来设置的,对格式要求比较严格,必须严格区分大小写,等号两边不能有空格,每行的最后也不能有空格.每个参数都有一个默认值,没有在配置文件中明确指定的参数就会使用默认值.我们这里不理会配置文件本来的信息,把所有内容都删掉或注释掉,最后加上下面四行,每行右边的//及后的文字是含义说明,不要输入到文件中:
listen=yes //vsftpd工作在standalone 模式下
anonymous_enable=yes //允许匿名用户登陆服务器
local_enable=yes //允许本地用户登录到服务器
pam_service_name=vsftpd //使用PAM认证
vsftpd有两种工作模式,standalone模式和xinetd守护进程模式,第1行就是让其工作在standalone模式下.此种模式中,每次修改配置文件必须重新启动vsftpd服务才能生效,关于两种模式在后面有详细介绍.我们安装时还把Redhat目录下的vsftpd.pam文件复制成了/etc/pam.d/vsftpd文件.这个文件就是本地用户登陆的pam验证配置文件.关于这个文件我们会在后面具体介绍.这里我们要知道,必须得有这个配置文件,而且主配置文件里要加上pam_service_name=vsftpd语句,我们才能让本地用户登陆.用以下命令启动服务:
# /usr/local/sbin/vsftpd /etc/vsftpd/vsftpd.conf &
为保证服务确实启动,我们用如下命令检测:
# netstat -an |grep 21
tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN
我们看到服务器已经打开了tcp21端口,表明ftp确实已经启动.再登录服务器:
[root@server vsftpd]# ftp localhost
Connected to localhost (127.0.0.1).
220 (vsFTPd 2.1.0)
Name (localhost:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
这时我们已经用匿名用户(用户名ftp或anonymous,密码任意)登录到服务器了,还可以用本地用户登录.我们做测试时建议使用如上所示的ftp命令(windows、Linux及Unix都带这个命令,用法都是一样的)来登录服务器,这样可以看到更详细的信息,对于我们调试服务器是非常有帮助的.最简单的ftp服务器就已经达建起来了.使用如下命令关闭ftp服务:
# killall vsftpd
服务启动脚本的制作
在standalone模式中,经常用上面的命令启动服务比较麻烦,我们做一个脚本来启动和停止服务.
建立一个新文件/etc/rc.d/init.d/vsftpd,把以下内容复制到文件中:
#!/bin/bash
#
# vsftpd This shell script takes care of starting and stopping
# standalone vsftpd.
#
# chkconfig: - 60 50
# description: Vsftpd is a ftp daemon, which is the program \
# that answers incoming ftp service requests.
# processname: vsftpd
# config: /etc/vsftpd/vsftpd.conf
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
[ -x /usr/local/sbin/vsftpd ] || exit 0
RETVAL=0
prog="vsftpd"
start() {
# Start daemons.
if [ -d /etc/vsftpd ] ; then
for i in `ls /etc/vsftpd/*.conf`; do
site=`basename $i .conf`
echo -n $"Starting $prog for $site: "
/usr/local/sbin/vsftpd $i &
RETVAL=$?
[ $RETVAL -eq 0 ] && {
touch /var/lock/subsys/$prog
success $"$prog $site"
}
echo
done
else
RETVAL=1
fi
return $RETVAL
}
stop() {
# Stop daemons.
echo -n $"Shutting down $prog: "
killproc $prog
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
return $RETVAL
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
stop
start
RETVAL=$?
;;
condrestart)
if [ -f /var/lock/subsys/$prog ]; then
stop
start
RETVAL=$?
fi
;;
status)
status $prog
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|restart|condrestart|status}"
exit 1
esac
exit $RETVAL
保存文件,再给该文件加上执行权限:
# chmod 755 /etc/rc.d/init.d/vsftpd
把vsftpd添加进系统初始化时候的服务列表.
# chkconfig --add vsftpd
这样我们就可以通过下面的方法来管理服务了:
# service vsftpd {start|stop|restart|condrestart|status}
例如重新启动服务:
# service vsftpd restart
Shutting down vsftpd: [OK ]
Starting vsftpd for vsftpd: [OK ]
四.配置文件详解
vsftpd配置文件只有一个,就是/etc/vsftpd/vsftpd.conf,上一小节我们就已经加入了两行参数了.在修改了配置文件之后,需要重新启动服务才能生效.下面我们就来详细解释其中的参数.
1.匿名及本地用户共同参数
write_enable=yes/no //是否允许全局可写
download_enable=yes/no //是否允许所有用户可以下载
dirlist_enable=yes/no //是否允许所有用户可以浏览(列出文件列表)
我们将write_enable=no、download_enable=yes两行加入配置文件,再测试:
[root@server ~]# ftp localhost
Connected to localhost (127.0.0.1).
220 (vsFTPd 2.1.0)
Name (localhost:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> put hello.txt
local: hello.txt remote: hello.txt
227 Entering Passive Mode (127,0,0,1,249,159).
550 Permission denied.
ftp> get filetest
local: filetest remote: filetest
227 Entering Passive Mode (127,0,0,1,209,139).
150 Opening BINARY mode data connection for filetest (6 bytes).
226 File send OK.
6 bytes received in 0.00502 secs (1.2 Kbytes/sec)
ftp>
如上所示,我们看到了ftp上的文件,可以下载文件,但不可以上传文件.如果把dirlist_enable=no也加上,便无法看到ftp上的文件(无法列出文件列表),但是如果你知道具体的文件名及路径,仍然可以下载文件的.实验结果就不贴上来了.
再看下一组:
ftpd_banner=欢迎语字符串
banner_file=文件
dirmessage_enable=yes/no
message_file=文件
参数ftpd_banner设置的欢迎语字符串将在登录时看到,如果想做出多行欢迎语,就要把内容单独存为banner_file参数指定的文件,应用中这两个参数二选一即可.dirmessage_enable和message_file参数是进入某个目录后显示的欢迎信息,用法与前两个参数一样.
2.本地用户管理
2.1.本地用户常规配置参数
local_root=/path //本地用户登陆服务器后直接进入的目录
local_umask=八进制数 //本地用户上传档案权限的umask值
local_max_rate=数字 //本地用户传输速率单位为bps
chmod_enable=yes/no //是否允许本地用户改变ftp服务器上档案的权限
我们知道使用本地用户登录ftp后进入的是用户的主目录,local_root这个参数允许我们登录服务器后直接进入其它的目录.此功能结合Apache的userdir模块来实现网站内容更新上传是非常方便的.Linux系统中的任何文件都是有权限值的,上传的文件也不例外,这个默认的权限值就由local_umask参数指定.其计算方法为:
默认建立文件的权限+local_umask=0666
默认建立目录的权限+local_umask=0777
由此我们可以看出,上传的文件无论如何都不可能有执行权限的.这也是vsftp安全性的体现啊!
local_max_rate参数限定了数据传输速率,包括上传和下载.chmod_enable参数限制用户是否可以改变档案权限(使用chmod, site命令).
我们可能想为每个用户进行单独的配置,或者想配置个别用户的权限.这样就得为每个本地用户配置一个文件.这些配置文件必须是在同一个目录下,所以我们可以设置本地用户单独配置文件所在的目录:
user_config_dir=/path //用户单独配置文件所在目录
我们在配置文件中加入以下几行:
local_umask=077
local_max_rate=20000
user_config_dir=/etc/vsftpd/vsftpd_user_config
给予用户上传权限:
write_enable=yes
新建一个普通用户huabo,再新建一个目录/etc/vsftpd/vsftpd_user_config,其下建一个文件huabo,里面加入下面几行:
local_root=/var/www/html
local_umask=022
local_max_rate=50000
把/var/www/html的所有者改为huabo:
chown huabo:huabo /var/www/html
测试之后我们发现,使用ioo用户登录后就直接进入var/www/html了,上传的文件(夹)权限为644(755),传输速率为50k,自定义的设置覆盖了主配置文件中的设置.
2.2.本地用户登录限制参数
在我们的服务器上本来就有很多的本地用户,这些本地用户应该都是可以登陆ftp服务器的.但是ftp服务是以明文传输的,如果允许管理员登陆的话,这种机制显然不好.又或者我们只想让一些本地用户可以登陆,或者一些不能登陆我们的ftp服务器,这样我们可以怎么设置呢?
Vsftpd提供了userlist功能.它使用一个文件来保存一些用户名,然后根据配置来决定是文件中的用户可以登录还是文件中没有列出的用户可以登陆ftp服务器,这样就对本地用户的登陆起到了限制作用.其配置参数有如下几个:
userlist_enable=yes/no //是否启用userlist功能模块
userlist_deny=yes/no //是否拒绝userlist文件中用户登陆ftp服务
userlist_file=/path/to/file //指定的userlist文件名
当第1个参数值为yes时,第2-3行才起作用.我们将配置文件加上如下3行:
userlist_enable=yes
userlist_deny=yes
userlist_file=/etc/vsftpd/vsftpd.userlist
然后再新建一个文件/etc/vsftpd/vsftpd.userlist,在里面加入用户名,每个用户名一行,比如我这里加入用户root,再登录服务时出现以下信息:
[root@server ~]# ftp localhost
Connected to localhost (127.0.0.1).
220 (vsFTPd 2.1.0)
Name (localhost:root): root
530 Permission denied.
Login failed.
root用户已经不能登录了,在输入密码之前就被拒绝,但其它用户还可以登录的.如果把userlist_deny的值改为no,则只有文件中的用户才可以登录服务器.
2.3.本地用户的根目录参数
大家再来看下面这一段:
[root@server ~]# ftp localhost
Connected to localhost (127.0.0.1).
220 (vsFTPd 2.1.0)
Name (localhost:root): huabo
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> pwd
257 "/home/huabo"
ftp> cd /
250 Directory successfully changed.
ftp> pwd
257 "/"
ftp> ls
227 Entering Passive Mode (127,0,0,1,137,190).
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 Apr 24 08:47 bin
drwxr-xr-x 3 0 0 4096 Mar 19 04:22 boot
是不是感到吃惊了!我们用本地用户登录ftp服务器,却可以看到整个服务器的目录和文件,甚至还可以把/etc/passwd文件下载下来,这是非常不安全的,我们应该禁止这个功能,限制用户只能在自己的目录里浏览,这就要用到chroot功能.看下面三个参数:
chroot_list_enable=yes/no //是否启用chroot_list文件
chroot_local_user=yes/no //是否限制本地用户的根目录为自己的主目录
chroot_list_file=/path/to/file //设置 chrootlist 文件名
我们新建一个用户huahua,再新建一个文件/etc/vsftpd/vsftpd.chroot_list,其中加入huahua.然后在配置文件中添加以下几行:
chroot_list_enable=yes
chroot_local_user=yes
chroot_list_file=/etc/vsftpd/vsftpd.chroot_list
再测试时,可以看到,在文件/etc/vsftpd/vsftpd.chroot_list中的用户huahua根目录仍然是系统根目录,但不在文件中的用户根目录已经变成了"/",就是说列在文件外的用户已经不能在自己主目录范围外浏览了.
3.匿名用户参数
我们可以认为,本地用户进入自己主目录本身就应有比较大的权限,所以我们看到本地用户受限的语句不多.但是匿名用户通常涉及到一个公开,公共的互联网环境,所以限制匿名用户的权限语句就比较多,限制也比较细致.看看这一组参数:
anon_upload_enable=yes/no //是否允许匿名用户上传
anon_mkdir_write_enable=yes/no //是否允许匿名用户建立文件夹
anon_other_write_enable=yes/no //是否允许匿名用户可以使用除了建立文件夹和上传文件以外其他的ftp写操作命令.例如:delete、rename等等
anon_world_readable_only=yes/no //匿名用户是否允许下载所有用户都可以访问的文件
我们先把配置文件清理一下,现在配置文件只有下面几行:
listen=yes
anonymous_enable=yes
write_enable=yes
download_enable=yes
dirlist_enable=yes
anon_upload_enable=yes
anon_mkdir_write_enable=yes
anon_other_write_enable=yes
我们希望匿名用户有上传文件的权限,但这里还只是在ftp服务里给了写权限,还必须在文件权限考虑实现.于是我们给/var/ftp加上写权限:
chmod a+w /var/ftp
然后登录服务器:
[root@server ~]# ftp localhost
Connected to localhost (127.0.0.1).
220 (vsFTPd 2.1.0)
Name (localhost:root): anonymous
331 Please specify the password.
Password:
500 OOPS: vsftpd: refusing to run with writable anonymous root
Login failed.
结果我们连服务器都登陆不了了!这是因为vsftpd出于在安全方面的考虑,不允许匿名用户对根目录有写权限.为此,我们只有去掉/var/ftp的写权限,再在其中新建一个目录,给予其写权限,让匿名用户上传文件到这个目录中.
# chmod 755 /var/ftp
# mkdir /var/ftp/upload
# chmod 777 /var/ftp/upload
现在我们可以匿名在upload里上传文件,建立文件夹,还可以删除改名等,但是却无法将上传的文件下载回来.如果你上传的文件是在一个新建的文件夹里,那么上传的文件不但下载不下来,而且连看都看不到.
这就要研究anon_world_readable_only这个参数了,它的默认值是yes.如果其值为yes,则匿名用户只可以下载所有用户都可访问的文件.比如:
# ll
total 40
-rw----r-- 1 ftp ftp 34935 05-13 17:38 install.log
-rw------- 1 ftp ftp 209 05-13 18:16 scsrun.log
这里install.log文件权限其它位上有r权限,那么这个文件就可以被下载;scsrun.log文件其它位上没有任何权限,所以这个文件就不能被匿名用户下载.
因此解决方法有两个,一是把参数anon_world_readable_only的值改为no;二是把上传文件默认权限的其它位上加上执行权限,这就用到下面这个参数:
anon_umask=八进制数
这个参数值的计算方法与本地用户local_umask参数一样,不在赘述.
在以上的实验中,大家可能已经注意到匿名用户上传的档案所有者为ftp,这们也可能用下面两个参数来改变档案所有者:
chown_uploads=yes/no //是否开启修改默认匿名上传档案所有者的功能
chown_username=本地用户名 //匿名上传档案的所有者名
匿名用户使用任何密码都是可以登陆服务器的,那么我们可以免了匿名用户登陆必须输入密码的步骤,只要我们在配置文件中加入:
no_anon_password=yes
匿名用户的参数还有很多,我们就不一一介绍了
到此,我们已经可以搭建出的ftp服务器已经可以满足很多场合的需要了,如果有要求更加苛刻的场合,那就还需要进一步设置.
4.IP监听与连接控制
vsftpd工作在独立模式(standalone)下的启动参数有两项:
listen=yes/no
listen_ipv6=yes/no
其中第一条已经前面已经提过了,第二条应用在ipv6网络环境中,这两个参数只能有一条值为yes.
在实际的网络环境中,服务器通常都有多个IP地址,而每个IP地址连接不同的网段,我们可能并不希望在所有网段的上的计算机都能访问服务器.而默认情况下,vsftpd将在所有的IP地址上监听,因此,我们需要下面两行:
listen_address=监听ip
listen_address6=监听ip
这两行分别是针对IPv4和IPv6环境的.
下面的两项是vsftpd并发连接控制:
max_clients=数字
max_per_ip=数字
参数max_clients设置了服务器可以接受的最大并发连接数量,max_per_ip设置了每个客户端IP可以发起的最大连接数.针对服务器性能适当设置这两个参数,可以在服务器可接受的连接数量和连接速度之间找到平衡点.这两项默认值均为0,表示无限制.
accept_timeout=数字
connect_timeout=数字
data_connection_timeout=数字
idle_session_timeout=数字
上面的数字都是以秒为单位的.其中access_timeout代表以pasv数据连接模式的时候,数据连接的超时;connect_timeout表示以port模式连接数据连接时的超时时间;关于ftp服务连接模式下面会有详细介绍.data_connection_timeout表示数据连接后数据连接等待的空闲时间超时,超过时间后,数据连接将断开连接;idle_session_timeout设置发呆时间,也就是客户端隔多长时间不与服务器有交互ftp命令,将自动断开ftp服务连接.
5.关于连接端口设置
我们知道ftp服务有一点是不同于其他的服务的是,ftp服务使用的是tcp双连接通道,也就是ftp-server和ftp-data连接.我们可以这么理解:ftp-server连接接受客户端连接请求,并发控制,身份和权限认证以及传输客户端下达的命令.ftp-data连接负责传输数据,也就是说当有数据传输的时候才会有这条连接.我们先来看一下ftp-server的设置:
listen_port=端口号
那么这条设置可以设置ftp-server端口号,默认为21,如果我们指定了其它端口号,那么客户端连接服务器上时就得使用指定端口号了.
接下来我们讨论ftp-data连接的问题.
FTP数据传输有两种模式:FTP Port模式和FTP Passive模式,两种工作方式截然不同.
FTP Port模式(主动模式)
在FTP Port模式下,客户端与服务器建立ftp-server连接之后,如果某条指令涉及到数据传送,就需要建立ftp-data连接.
连接步骤如下:
A.客户端的任何端口----到----FTP服务器的21端口(SC,服务器响应客户端的控制端口)
C.客户端开始监听自己的N号端口.
D.FTP服务器的20端口----到----客户端的大于1024的端口N(S->C,服务器端初始化数据连接到客户端的数据端口,20端口可通过配置文件改变)
E.客户端的大于1024的端口N----到----FTP服务器的20端口(SC,服务器回复"PORT N",告诉客户端,自己的N号端口可连接)
C.服务器开始监听自己的N号端口.
C.客户端的任何端口----到----服务器的N号端口(SC,服务器发送ACK响应和数据到客户端的数据端口)
在第1步中,客户端的命令端口与服务器的命令端口建立连接,并发送命令"PASV".然后在第2步中,服务器返回命令"PORT 2024",告诉客户端(服务器)用哪个端口侦听数据连接.在第4步中,客户端初始化一个从自己的数据端口到服务器端指定的数据端口的数据连接,最后服务器在第5步中给客户端的数据端口返回一个"ACK"响应.
被动方式的FTP解决了客户端的许多问题,但同时给服务器端带来了更多的问题.最大的问题是需要允许从任意远程终端到服务器高位端口的连接.幸运的是,许多FTP守护程序,包括Vsftpd允许管理员指定FTP服务器使用的端口范围.
接下来我们来看看vsftpd中关于Passive模式中设置语句:
pasv_enable=yes/no
pasv_min_port=port_number
pasv_max_port=port_number
pasv_promiscuous=yes/no
pasv_address=ip_address
第一行设置是否启用pasv模式.pasv_min_port和pasv_max_port是设置在pasv模式下开启的端口范围.一般情况下,如果设置成pasv模式,我们最好指定端口范围,便于防火墙设置开启这个范围的端口以接受客户端的连接请求.pasv_promiscuous与port_promiscuous参数一样是设置在pasv下是否设置安全的传输,我们也要将其值设为no(默认值即为no).pasv_address后接一个有效的ip地址,来指定pasv打开端口的ip地址.但是默认情况下这行是取消的,因为服务会在tcp连接的套接字中知道连接的ip地址.我们把主配置文件改成这样然后看一下设置效果:
pasv_enable=yes
pasv_min_port=3000
pasv_max_port=3003
登录服务器运行3次ls命令,再在服务器端运行netstat命令查看效果:
# netstat -an
tcp 0 0 127.0.0.1:3002 127.0.0.1:54098 TIME_WAIT -
tcp 0 0 127.0.0.1:3003 127.0.0.1:44106 TIME_WAIT -
tcp 0 0 127.0.0.1:3003 127.0.0.1:34868 TIME_WAIT -
我们看到,每次ls命令产生了一个连接,服务器开的端口是3000和3003之间.在vsftpd2.0.3以后的版本中,pasv端口允许我们重复开启,在之前的版本里是不允许的,也就是说同一个端口可以同时与客户端建立多条连接,大家可以自己试验一下.
大多数人认为在防火墙网络环境中Passive模式比Port模式的问题少,但我们注意到在Passive模式下,客户端向服务器端一个临时的目的端口发起连接,一些防火墙或者设备的访问控制列表(ACL)可能会阻止这种连接;同样服务器的回应也是从一个临时的端口到另一个临时的端口,防火墙或者访问列表也会阻止这种连接.在许多路由器和防火墙上(包括iptables)允许你使用访问列表关键字"established"来避免第二个问题,"established"关键字告诉路由器允许带ACK标志的包通过.而对于第一个问题,我们虽然使用pasv_min_port和pasv_max_port语句来限制服务器开设临时端口的范围,从而在防火墙上打开这些端口,但这样做还是存在一定的安全漏洞.好在多数状态检测防火墙例如Linux netfileters支持ftp协议的深层状态检测,进行准确的PASV动态端口过滤.
五.vsftpd高级操作
这一节我们介绍一下vsftpd的其它一些知识,其中包括:双模式切换,基于ip的虚拟ftp站点,基于数据库虚拟用户建立及管理,基于OpenSSL的加密数据传输.
1.vsftpd双模式切换
前面我们提过,vsftpd服务是支持在linux下的两种服务模式:独立(standalone)模式和守护进程(xinetd)模式.在standalone模式下,vsftpd进程启动后会一直占用系统资源,当有连接请求时,它会迅速反应;在xinetd模式下,ftp服务是由守护进程统一管理,当出现ftp连接请求时,守护进程才将ftp服务启动,这种方式最大的优点是没有连接的时候ftp服务不会占用系统资源,处于睡眠状态,但因为要花费时间去唤醒该服务,所以响应时间较长.
之前做的试验一直是把vsftpd做在独立模式下,下面我们把它移到守护进程下.注意在工作在守护进程下时,有的参数并不起作用,详细可查阅vsftpd帮助信息(man vsftpd.conf).
我们需要在守护进程配置目录/etc/xinetd.d/里建立vsftpd 的守护进程文件.我们在安装时已经将该文件考到/etc/xinetd.d/目录下了.我们稍稍修改其内容:
#vi /etc/xinetd.d/vsftpd
service ftp
{
disable = no
socket_type = stream
wait = no
user = root
server = /usr/local/sbin/vsftpd
server_args = /etc/vsftpd/vsftpd.conf
nice = 10
}
接下来把配置文件中的listen=yes或listen_ipv6=yes去掉,停掉vsftpd服务,重启xinetd服务:
# sesrvice vsftpd stop
# service xinetd restart
重新启动守护进程后,vsftpd服务就会让守护进程来管理了.在守护进程管理过程中,我们再修改主配置文件的话,就不需要重新启动服务了.
2.基于IP的虚拟ftp站点
这一小节我们来讨论在同一服务器上建立多个ftp站点,每个站点相互独立,拥有独立的配置文件.当然服务器必须有两个以上的IP地址.在standalone模式下,我们可以考虑启动多个ftp服务进程;在xinetd模式下,可以让守护进程来管理.下面我们分别讨论这两种情况.为简单起见,我们在服务器上建立两个匿名虚拟站点.下面是这两个站点的信息:
站点1:
ip地址:192.168.100.100
主配置文件:/etc/vsftpd/vsftpd.conf
匿名用户映射的本地用户名:ftp
匿名用户主目录:/var/ftp/
站点2:
ip地址:192.168.200.1
主配置文件:/etc/vsftpd/vsftpd2.conf
匿名用户映射的本地用户名:ftp2
匿名用户主目录:/var/ftp2/
standalone模式下虚拟站点的建立
首先我们修改站点1的配置文件/etc/vsftpd/vsftpd1.conf为下面所示:
listen=yes
listen_address=192.168.100.100
anonymous_enable=yes
local_enable=yes
pam_service_name=vsftpd
write_enable=yes
ftpd_banner=This is ftp1 site
站点1就这样配置完毕了.接下来为站点2建立ftp2的用户:
# mkdir /var/ftp2/
# useradd -d /var/ftp2/ ftp2
为了让站点2知道匿名用户的主目录为/var/ftp2,我们需要在配置文件中手动指定站点2使用ftp2用户登录,于是我们要用到下面这条语句:
ftp_username=local_username
建立站点2的配置文件/etc/vsftpd/vsftpd2.conf,内容如下:
listen=yes
listen_address=192.168.200.1
anonymous_enable=yes
local_enable=yes
pam_service_name=vsftpd
write_enable=yes
ftp_username=ftp2
ftpd_banner=This is ftp2 site
接下来我们启动vsftpd服务,就可以看到效果了.如果不用service vsftpd start命令来启动服务的话,就必须手动启动两次.
# /usr/local/sbin/vsftpd /etc/vsftpd/vsftpd.conf &
[1] 2287
# /usr/local/sbin/vsftpd /etc/vsftpd/vsftpd2.conf &
[1] 2288
测试结果如下:
[root@server ~]# ftp 192.168.100.100
Connected to 192.168.100.100 (192.168.100.100).
220 This is ftp1 site
Name (192.168.100.100:root): anonymous
......
[root@server ~]# ftp 192.168.200.1
Connected to 192.168.200.1 (192.168.200.1).
220 This is ftp2 site
Name (192.168.200.1:root):
我们在各自的配置文件设置了不同的banner,上面已经看到效果了.
守护进程模式下虚拟站点的建立
在standalone模式下,IP的绑定在配置文件里配置了,配置文件名及其位置在启动服务的命令参数里指定;在xinetd模式下,这两步需要在守护进程配置文件里配置.这样在守护进程里面我们就得用到这两个设置:
bind=绑定的ip
server_args=每个站点的配置文件
那么我们来做守护进程文件,首先来写站点1的守护进程文件:
# vi /etc/xinetd.d/vsftpd
service ftp
{
disable = no
socket_type = stream
wait = no
user = root
server = /usr/local/sbin/vsftpd
server_args = /etc/vsftpd/vsftpd.conf
nice = 10
bind = 192.168.100.100
}
再建立站点2的守护进程文件,并输入下面的内容:
# vi /etc/xinetd.d/vsftpd2
service ftp
{
disable = no
socket_type = stream
wait = no
user = root
server = /usr/local/sbin/vsftpd
server_args = /etc/vsftpd/vsftpd2.conf
nice = 10
bind = 192.168.200.1
}
这样两个守护进程文件就写完了,用户也在上个试验已经建立完了.接下来继续修改两个站点的配置文件,均是把listen,listen_address两行删去即可.现在我们可以重新启动xinetd服务,测试结果就不贴出来了.
3.关于TCP Wrappers
TCP Wrappers的作用,就是通过分析TCP网络数据包,根据其包头的IP地址和端口号,决定是否让这个数据进入到主机之中,因此我们也可以把它当成一个最内层的防火墙.数据包要进入ftp服务器,首先经过netfilter的过滤,通过TCP Wrappers筛选,守护进程(xinetd模式)限制,最后才能交由vsftpd进程来处理.
我们可以设置TCP Wrappers来限制某些主机能或者不能访问ftp服务器,这需要编辑两个文件:
/etc/hosts.allow
/etc/hosts.deny
当数据包通过TCP Wrappers筛选时,/etc/hosts.allow文件会首先读取,然后再读取/etc/hosts.deny文件,就是说/etc/hosts.allow优先级要高一些.这两个文件设置规则如下:
::
字段是服务名,也就是/etc/rc.d/init.d/目录下存在的文件名;第二个字段是可以是IP,域名,一台主机或者一个网段;第三个字段表示允许通过或者禁止.具体看下面的例子:
vsftpd:192.168.0.111:allow //允许主机192.168.0.111访问vsftpd服务器
httpd:10.100.1.0/255.255.255.0:deny //禁止10.100.1.0/24这个子网访问www服务
最后一个字段的:allow或:deny可以省略,写在/etc/hosts.allow文件里默认就是allow, /etc/hosts.deny文件里默认是deny.其实我们可以把所有语句都写在hosts.allow文件中,但建议大家把allow和deny的语句分别写到两个文件之中.
TCP Wrappers默认规则是允许所有数据包通过,所以大家在填写允许条目之后,一定还要加一条deny语句来拒绝其它的包.比如:
# vi /etc/hosts.allow
vsftpd:192.168.1.0/255.255.255.0 //允许192.168.1.0/24网段可以访问ftp
# vi /etc/hosts.deny
vsftpd:ALL //拒绝其它所有主机访问ftp
如果vsftpd工作在守护进程模式下,不但可以受到TCP Wrappers的筛选,还可以设置守护进程配置文件来进行同样的过滤,这使用下面两条语句:
only_from = //限制可以访问的IP,主机,网络
no_access = //限制不能访问的IP,主机,网络
下面我们将only_from语句加入/etc/xinetd.d/vsftpd文件中,实现只有子网192.168.100.128/25才可以登录ftp服务器:
service ftp
{
disable = no
socket_type = stream
wait = no
user = root
server = /usr/local/sbin/vsftpd
server_args = /etc/vsftpd/vsftpd.conf
nice = 10
only_from = 192.168.100.128/25
}
如果vsftpd工作在standalone模式下,必须在编译vsftpd之前修改头文件builddefs.h以支持TCP Wrappers,详情请参加软件安装小节.另外还需要在vsftpd主配置文件中加入tcp_wrappers=yes参数.
4.结合MySql数据库
将vsftpd与MySql相结合,我们可以把用户和日志信息放到数据库里面去,如果再结合php来管理数据库,则可以使vsftpd管理更加方便.下面我们就来讨论一下基于MySql的虚拟户和日志功能.
使用MySql来实现虚拟用户
前面我们介绍了两类用户,关于匿名用户的语句比较多,权限限制比较灵活;而本地用户的特点是每个用户对应一个密码和主文件夹,登录控制比较灵活.可不可以将两者的优点结合一下呢?答案是肯定的,这就是虚拟用户.关于虚拟用户的启用,需要使用以下两条语句:
guest_enable=yes/no
guest_username=user_name
上述guest_enable表示是否开启虚拟用户功能,guest_username表示虚拟用户登录后映射的本地用户名.如果开启虚拟用户功能,本地用户登录后将映射到guest_username参数指定的用户,主目录也变成该用户的主目录.
我们修改vsftpd主配置文件,变为下面的样子:
listen=yes
anonymous_enable=yes
local_enable=yes
pam_service_name=vsftpd
write_enable=yes
dirlist_enable=yes
download_enable=yes
anon_upload_enable=yes
anon_mkdir_write_enable=yes
anon_other_write_enable=no
anon_umask=073
guest_enable=yes
guest_username=virftp
再新建一个用户virftp改变一下其主目录的权限:
# useradd -d /var/virftp -s /sbin/nologin virftp
# chmod 704 /var/virftp
这时再以/etc/passwd中的用户登录ftp,通过查看内容,会发现主目录已经切换到/var/virftp/,可以下载和上传文件,但不能改名和删除.这就是说,限制匿名用户的参数也同样适用于本地用户.
如果想让虚拟用户像本地用户那样拥有每个用户独立的主目录,独立的配置文件和权限,又该怎么办呢?还记得user_config_dir参数吧!在每个用户独立的配置文件里设定不同的权限和local_root参数就可以了.
再来看看这个参数:
virtual_use_local_privs=yes/no
从刚才的实验可以看到,虚拟用户登录后,受到匿名用户参数的限制.我们可以通将此参数的值改为yes,则虚拟用户会变得和本地用户一样,拥有和本地用户一样的特权.由于我们平常都是看中了匿名用户限制参数比较细致这个特点才启用虚拟用户的,所以此参数默认值为no!
下面我们结合MySql,把用户登录信息放到数据库里面去.
(MySQL的安装过程省略)
建立数据库ftpdb:
mysql> create database ftpdb;
在数据库ftpdb中建立一个表ftpuser,表中有username和password字段:
mysql> use ftpdb;
Database changed
mysql> create table ftpuser(username char(20) not null, password char(64) not null);
Query OK, 0 rows affected (0.15 sec)
这里要注意密码字段的长度,不同的算法生成的密文长度是不一样的,建议不要少于50位,否则可能导致密文在存储时被截短.
我们插入两条记录作为两个ftp的登录名和密码,使用mysql自带的password函数来加密密码:
mysql> insert into ftpuser values('test1','abc');
Query OK, 1 row affected, 1 warning (0.08 sec)
mysql> insert into ftpuser values('test2','123');
Query OK, 1 row affected, 1 warning (0.00 sec)
然后我们再建立一个可以让ftp服务登陆数据库的用户:
mysql> grant select on ftpdb.ftpuser to ftpdb_query@localhost identified by 'P@ssw0rd';
这个用户只能浏览ftpdb数据库下的ftpuser表中内容,我们如果想以后分配一个可以完全管理ftpdb数据库的用户,再这样:
mysql> grant all on ftpdb.* to ftpdb_all@localhost identified by 'P@ssw0rd';
到这里MySql的设置就算完了,接下来安装PAM基于mysql数据库的认证插件.
(安装过程省略)
然后来编写PAM认证文件:
# vi /etc/pam.d/ftpdb
auth required /lib/security/pam_mysql.so user=ftpdb_query passwd=P@ssw0rd host=localhost db=ftpdb table=ftpuser usercolumn=username passwdcolumn=password crypt=0
account required /lib/security/pam_mysql.so user=ftpdb_query passwd=P@ssw0rd host=localhost db=ftpdb table=ftpuser usercolumn=username passwdcolumn=password crypt=0
注意,整个这个文件中只有auth和account两行内容,中途不要加回车换行;文件中不要再有包含其它pam模块的行;如果pam_mysql.so文件没有在/lib/security目录,就需要指定文件路径.文件中其它字段的意思是:
user 访问数据库用户名
passwd 访问数据库用户密码
host 数据库主机
db 数据库名
table 表名
usercolumn 用户列名
passwdcolumn 密码列名
crypt 密码验证机制;0代表明文,1代表DES加密,2代表Mysql的password()函数加密,3代表md5算法,4代表sha加密.
现在我们修改vsftpd主配置文件/etc/vsftpd/vsftpd.conf,把pam_service_name的值改为ftpdb,也就是我们刚才建立的那个PAM认证文件的名字.再登录服务器测试,可以发现/etc/passwd中的用户已经无法登录到服务器了,而数据库中存储的用户名是可以登录的.我们还可以按前面所述的方法为每个虚拟用户建立独立的配置文件,指定独立的主目录;还可以结合apache服务建立php页面,然后实现让用户在web界面注册帐号,修改密码,这要比原来的认证方式灵活得多.
在MySql中记录日志
接下来我们看一下如何利用刚才的PAM模块来结合mysql数据库记录vsftpd服务的日志.在介绍之前,我们来看看vsftp中关于日志记录的参数.
xferlog_enable=yes/no //是否启用 xferlog 日志格式
xferlog_std_format=yes/no //是否采用标准格式记录日志
xferlog_file=/path/to/logfile //xferlog 日志文件所在位置,默认为/var/log/xferlog
上面的参数设置记录xferlog日志的格式.这是早期Wu-ftpd服务的日志格式,它会记录上传和下载的动作.vsftpd也有专有的日志格式,用下列参数设置:
dual_log_enable=yes/no //是否采用Vsftpd自己的日志记录方式
log_ftp_protocol=yes/no //是否记录所有的ftp命令日志
vsftpd_log_file=/path/to/logfile //指定vsftpd日志文件位置,默认为/var/log/vsftpd.log
xferlog_enable的默认值为no(vsftpd提供的配置文件模版将其值改为了yes),dual_log_enable的默认值也为no,就是说默认情况下vsftpd是不记录日志的.我们也可以将日志信息写入系统日志/var/log/messages中,使用如下参数:
syslog_enable=yes/no
还是建议大家把日志记录为单独的文件,以便浏览和管理.实验比较简单,我们就不做了.
对于使用文件来记录日志的方式来说,我们必须登录到服务器之后,才能查看日志.这样做不方便,不灵活.我们可以把日志放到数据库中,结合www服务建立一个浏览日志的页面,这样就非常舒服的看到web方式的日志了.下面来看看如何将日志写入数据库中去.
首先必须使用虚拟用户所在的同一个数据库,新建立存储日志的表:
mysql> create table ftplog
-> (log char(100),
-> user char(20),
-> host char(20),
-> time datetime,
-> pid int);
修改 PAM 配置文件,在原来的基础上我们改动一下:
# vi /etc/pam.d/ftpdb
auth required /usr/lib/security/pam_mysql.so user=ftpdb_all passwd=P@ssw0rd host=localhost db=ftpdb table=ftpuser usercolumn=username passwdcolumn=password crypt=2 sqllog=yes logtable=ftplog logmsgcolumn=log logusercolumn=user loghostcolumn=host logtimecolumn=time logpidcolumn=pid
account required /usr/lib/security/pam_mysql.so user=ftpdb_all passwd=P@ssw0rd host=localhost db=ftpdb table=ftpuser usercolumn=username passwdcolumn=password crypt=2 sqllog=yes logtable=ftplog logmsgcolumn=log logusercolumn=user loghostcolumn=host logtimecolumn=time logpidcolumn=pid
注意在这个文件中依然就是原来的两行,其中加入的内容分别对应如下:
sqllog 表示是否将日志记录到数据库中
logtable 记录日志的表名
logmsgcolumn 记录日志信息的列
logusercolumn 登录用户
loghostcolumn 登录主机
logtimecolumn 登录时间
logpidcolumn 处理该用户连接的进程pid
这次我换了一个登陆数据库用户,使用先前建立的有完全权限的用户ftpdb_all,这个用户才有在数据库中使用insert命令的权限.
5.结合OpenSSL实现加密数据传输
FTP的一个声名狼藉的问题是它以明文方式发送用户名和口令.任何人只要在网络中合适的位置进行抓包分析就可以看到用户名和口令;FTP发送的数据也是以明文方式传输,通过对ftp连接的监控和数据收集就可以重现ftp的数据传输.如:
[root@server ~]# tcpdump -i eth2 -A
......
17:13:33.734512 IP 192.168.10.8.39407 > 192.168.10.1.ftp: P 1:15(14) ack 21 win 1460
E..B..@.@..R..
...
.....v.6ed.......8......
..F..9..USER userone(用户名)
......
17:13:35.350807 IP 192.168.10.8.39407 > 192.168.10.1.ftp: P 15:28(13) ack 55 win 1460
E..A..@.@..Q..
...
.....v.6sd........i.....
..Q,.9..PASS 123456(密码,很恐怖吧)
......
很多用户为了方便把相同的用户名和口令用在不同的应用中,如果黑客收集到FTP口令,他们也可能就得到了你在线帐号或者其他一些机密数据的口令.
SSL(Secure Socket Layer)工作于传输层和应用程序之间.作为一个中间层,应用程序只要采用SSL提供的一套SSL套接字API来替换标准的Socket套接字,就可以把程序转换为SSL化的安全网络程序,在传输过程中将由SSL协议实现数据机密性和完整性的保证.SSL取得大规模成功后,IETF将SSL作了标准化,并将其称为TLS(Transport Layer Security).Ftp结合SSL,将实现传输数据的加密,保证数据不被别人窃取.
要让vsftpd支持SSL,必须在安装之前修改头文件builddefs.h,将#undef VSF_BUILD_SSL行改为#define VSF_BUILD_SSL,在安装小节已经讲过.这里我们用OpenSSL结合vsftpd来实现数据加密传输.首先查看自己的系统有没有安装OpenSSL,如果没有安装,到http://www.openssl.org/source/下载安装,安装过程很简单,就不贴出来了.
下面我们为vsftpd生成证书:
# cd /etc/vsftpd/
# openssl req -new -x509 -nodes -out vsftpd.pem -keyout vsftpd.pem
Generating a 1024 bit RSA private key
.........................++++++
.............++++++
writing new private key to 'vsftpd.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) [GB]:cn
State or Province Name (full name) [Berkshire]:ShiChuan
Locality Name (eg, city) [Newbury]:ChenDu
Organization Name (eg, company) [My Company Ltd]:linuxer
Organizational Unit Name (eg, section) []:linuxer
Common Name (eg, your name or your server's hostname) []:www.linuxer.cn
Email Address []:icecard@hotmail.com
填写这些信息后,就产生了/etc/vsftpd/vsftpd.pem证书文件,接下来我们在配置文件中加入下面两行:
ssl_enable=yes
rsa_cert_file=/etc/vsftpd/vsftpd.pem
现在我们用RedHat自带的ftp命令登录服务器测试时,发现已经不能登录了,可能是这个ftp客户端不支持ssl的原因吧!在windows下支持ssl的ftp客户端很多(IE是不支持的),比如FlashFXP,使用比较简单,相信大家都会使用.我们这里介绍Linux下使用lftp来登录服务器.很多Linux发行版中都已经包含了lftp软件包,如果你的Linux中没有lftp,到http://lftp.yar.ru/get.html下载原码包来安装.
# lftp 127.0.0.1
lftp 127.0.0.1:~> user test1
口令:
lftp test1@127.0.0.1:~> ls
-rw-r--r-- 1 0 0 5 May 17 21:35 virftp.file
drwxrwxrwx 2 500 500 4096 May 17 21:47 woo
同时我们打开tcpdump抓包测试:
# tcpdump -i lo -A
......
23:32:15.237079 IP localhost.localdomain.ftp > localhost.localdomain.46605: P 36:47(11) ack 7 win 512
..yI...U.....3.........
..M7..M5 AUTH SSL
启用了SSL
23:32:15.272496 IP localhost.localdomain.46605 > localhost.localdomain.ftp: . ack 47 win 513
.....U..yT....9......
..M@..M6
23:32:15.272570 IP localhost.localdomain.ftp > localhost.localdomain.46605: P 47:137(90) ack 7 win 512
..yT...U...............
..M@..M@ AUTH TLS
EPRT
EPSV
MDTM
23:32:15.272605 IP localhost.localdomain.46605 > localhost.localdomain.ftp: . ack 137 win 513
.....U..y.....9i.....
..M@..M@
23:32:15.273156 IP localhost.localdomain.46605 > localhost.localdomain.ftp: P 7:17(10) ack 137 win 513
.....U..y......2.....
..M@..M@AUTH TLS
使用TLS认证方式,这是Vsftpd默认的安全认证方式.此时抓到的包已经使用TLS加密了,数据也是加密的,再也不怕第三方窃听了.
上面的例子只使用了两条配置语句,vsftp还提供了下面的语句来设置ssl:
ssl_enable=yes/no //是否启用 SSL,默认为no
allow_anon_ssl=yes/no //是否允许匿名用户使用SSL,默认为no
rsa_cert_file=/path/to/file //rsa证书的位置
dsa_cert_file=/path/to/file //dsa证书的位置
force_local_logins_ssl=yes/no //非匿名用户登陆时是否加密,默认为yes
force_local_data_ssl=yes/no //非匿名用户传输数据时是否加密,默认为yes
force_anon_logins_ssl=yes/no //匿名用户登录时是否加密,默认为no
force_anon_data_ssl=yes/no //匿名用户数据传输时是否加密,默认为no
ssl_sslv2=yes/no //是否激活sslv2加密,默认no
ssl_sslv3=yes/no //是否激活sslv3加密,默认no
ssl_tlsv1=yes/no //是否激活tls v1加密,默认yes
ssl_ciphers=加密方法 //默认是DES-CBC3-SHA
大家自行加入其它语句来满足自己的需要,如有疑问参考http://vsftpd.beasts.org/,man vsftpd.conf,多多阅读软件源码包中的README文件.
六.FTP展望
FTP是在70年代设计出来的,当时的互联网是一个封闭的网络,与现代网络环境还是有很大的差异,现代网络中不管你使用Port模式还是Passive模式,都可能产生问题.很多人对FTP协议安全性进行不懈的努力,使用SSL/TLS进行ftp传输过程的验证和加密,基本解决明文传数据的问题.但还是存在不少缺陷,于是出现了一些FTP替代应用,如SCP,SFTP;如果你使用ftp更新你的网页,还可以考虑WebDAV.
在FTP服务器软件中,vsftpd可以说是最安全的ftp软件,短小精悍,且高性能,是ftp服务器软件中的佼佼者.经过上面的学习,对于搭建安全高效的FTP服务器,再也不会困惑了.
参考资料: