免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1523 | 回复: 0
打印 上一主题 下一主题

[FreeBSD] FreeBSD下构建安全的Web服务器(3) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-09 13:20 |只看该作者 |倒序浏览
2. PHP安全设置

PHP本身再老版本有一些问题,比如在 php4.3.10和php5.0.3以前有一些比较严重的bug,所以推荐使用新版。另外,目前闹的轰轰烈烈的SQL Injection也是在PHP上有很多利用方式,所以要保证安全,PHP代码编写是一方面,PHP的配置更是非常关键。
我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最主要就是要配置php.ini中的内容,让我们执行php能够更安全。
整个PHP中的安全设置主要是为了防止phpshell和SQL Injection的攻击,一下我们慢慢探讨。我们先使用任何编辑工具打开/etc/local/apache2/conf/php.ini,如果你是采用其他方式安装,配置文件可能不在该目录。
(1) 打开php的安全模式
hp的安全模式是个非常重要的内嵌的安全机制,能够控制一些php中的函数,比如system(),同时把很多文件操作函数进行了权限控制,也不允许对某些关键文件的文件,比如/etc/passwd,但是默认的php.ini是没有打开安全模式的,我们把它打开:
afe_mode = on
(2) 用户组安全
当safe_mode打开时,safe_mode_gid被关闭,那么php脚本能够对文件进行访问,而且相同组的用户也能够对文件进行访问。
建议设置为:
afe_mode_gid = off
如果不进行设置,可能我们无法对我们服务器网站目录下的文件进行操作了,比如我们需要对文件进行操作的时候。
(3) 安全模式下执行程序主目录
如果安全模式打开了,但是却是要执行某些程序的时候,可以指定要执行程序的主目录:
afe_mode_exec_dir = /usr/bin
一般情况下是不需要执行什么程序的,所以推荐不要执行系统程序目录,可以指向一个目录,然后把需要执行的程序拷贝过去,比如:
afe_mode_exec_dir = /tmp/cmd
但是,我更推荐不要执行任何程序,那么就可以指向我们网页目录:
afe_mode_exec_dir = /usr/www
(4) 安全模式下包含文件
如果要在安全模式下包含某些公共文件,那么就修改一下选项:
afe_mode_include_dir = /usr/www/include/
其实一般php脚本中包含文件都是在程序自己已经写好了,这个可以根据具体需要设置。
(5) 控制php脚本能访问的目录
使用open_basedir选项能够控制PHP脚本只能访问指定的目录,这样能够避免PHP脚本访问/etc/passwd等文件,一定程度上限制了phpshell的危害,我们一般可以设置为只能访问网站目录:
open_basedir = /usr/www
(6) 关闭危险函数
如果打开了安全模式,那么函数禁止是可以不需要的,但是我们为了安全还是考虑进去。比如,我们觉得不希望执行包括system()等在那的能够执行命令的php函数,或者能够查看php信息的phpinfo()等函数,那么我们就可以禁止它们:
disable_functions = system,passthru,exec,shell_exec,popen,phpinfo
如果你要禁止任何文件和目录的操作,那么可以关闭很多文件操作
disable_functions = chdir,chroot,dir,getcwd,opendir,readdir,scandir,fopen,unlink,delete,copy,mkdir,rmdir,rename,file,file_get_contents,fputs,fwrite,chgrp,chmod,chown
以上只是列了部分不叫常用的文件处理函数,你也可以把上面执行命令函数和这个函数结合,就能够抵制大部分的phpshell了。
(7) 关闭PHP版本信息在http头中的泄漏
我们为了防止黑客获取服务器中php版本的信息,可以关闭该信息斜路在http头中:
expose_php = Off
比如黑客在 telnet
http://www.target.com:80
的时候,那么将无法看到PHP的信息。
( 关闭注册全局变量
在PHP中提交的变量,包括使用POST或者GET提交的变量,都将自动注册为全局变量,能够直接访问,这是对服务器非常不安全的,所以我们不能让它注册为全局变量,就把注册全局变量选项关闭:
register_globals = Off
当然,如果这样设置了,那么获取对应变量的时候就要采用合理方式,比如获取GET提交的变量var,那么就要用$_GET['var']来进行获取,这个php程序员要注意。
(9) 打开magic_quotes_gpc来防止SQL注入
SQL注入是非常危险的问题,小则网站后台被入侵,重则整个服务器沦陷,所以一定要小心。php.ini中有一个设置:
magic_quotes_gpc = Off
这个默认是关闭的,如果它打开后将自动把用户提交对sql的查询进行转换,比如把 ' 转为 \'等,这对防止sql注射有重大作用。所以我们推荐设置为:
magic_quotes_gpc = On
(10) 错误信息控制
一般php在没有连接到数据库或者其他情况下会有提示错误,一般错误信息中会包含php脚本当前的路径信息或者查询的SQL语句等信息,这类信息提供给黑客后,是不安全的,所以一般服务器建议禁止错误提示:
display_errors = Off
如果你却是是要显示错误信息,一定要设置显示错误的级别,比如只显示警告以上的信息:
error_reporting = E_WARNING & E_ERROR
当然,我还是建议关闭错误提示。
(11) 错误日志
建议在关闭display_errors后能够把错误信息记录下来,便于查找服务器运行的原因:
log_errors = On
同时也要设置错误日志存放的目录,建议根apache的日志存在一起:
error_log = /usr/local/apache2/logs/php_error.log
注意:给文件必须允许apache用户的和组具有写的权限。

3. Mysql的安全设置

我们把Mysql安装在 /usr/local/mysql目录下,我们必须建立一个用户名为mysql,组为mysql的用户来运行我们的mysql,同时我们把它的配置文件拷贝到 /etc目录下:
# cp suport-files/my-medium.cnf /etc/my.cnf
chown root:sys /etc/my.cnf
chmod 644 /etc/my.cnf
使用用户mysql来启动我们的mysql:
# /usr/local/mysql/bin/mysqld_safe -user=mysql &
(1) 修改root用户的的口令
缺省安装的mysql是没有密码的,所以我们要修改,以防万一。下面采用三种方式来修改root的口令。
*  用mysqladmin命令来改root用户口令
# mysqladmin -uroot password test
这样,MySQL数据库root用户的口令就被改成test了。(test只是举例,我们实际使用的口令一定不能使用这种易猜的弱口令)
*  用set password修改口令:
mysql> set password for
root@localhost=password('test&#39
;
这时root用户的口令就被改成test了。
*  直接修改user表的root用户口令   
mysql> use mysql;
mysql> update user set password=password('test&#39 where user='root';
mysql> flush privileges;
这样,MySQL数据库root用户的口令也被改成test了。其中最后一句命令flush privileges的意思是强制刷新内存授权表,否则用的还是缓冲中的口令,这时非法用户还可以用root用户及空口令登陆,直到重启MySQL服务器。
(2) 删除默认的数据库和用户
我们的数据库是在本地,并且也只需要本地的php脚本对mysql进行读取,所以很多用户不需要。mysql初始化后会自动生成空用户和test库,这会对数据库构成威胁,我们全部删除。
我们使用mysql客户端程序连接到本地的mysql服务器后出现如下提示:
mysql> drop database test;
mysql> use mysql;
mysql> delete from db;
mysql> delete from user where not(host="localhost" and user="root";
mysql> flush privileges;
(3) 改变默认mysql管理员的名称
这个工作是可以选择的,根据个人习惯,因为默认的mysql的管理员名称是root,所以如果能够修改的话,能够防止一些脚本小子对系统的穷举。我们可以直接修改数据库,把root用户改为"admin"
mysql> use mysql;
mysql> update user set user="admin" where user="root";
mysql> flush privileges;
(4) 提高本地安全性
提高本地安全性,主要是防止mysql对本地文件的存取,比如黑客通过mysql把/etc/passwd获取了,会对系统构成威胁。mysql对本地文件的存取是通过SQL语句来实现,主要是通过Load DATA LOCAL INFILE来实现,我们能够通过禁用该功能来防止黑客通过SQL注射等获取系统核心文件。
禁用该功能必须在 my.cnf 的[mysqld]部分加上一个参数:
et-variable=local-infile=0
(5) 禁止远程连接mysql
因为我们的mysql只需要本地的php脚本进行连接,所以我们无需开socket进行监听,那么我们完全可以关闭监听的功能。
有两个方法实现:
* 配置my.cnf文件,在[mysqld]部分添加 skip-networking 参数
* mysqld服务器中参数中添加 --skip-networking 启动参数来使mysql不监听任何TCP/IP连接,增加安全性。如果要进行mysql的管理的话,可以在服务器本地安装一个phpMyadmin来进行管理。
(6) 控制数据库访问权限
对于使用php脚本来进行交互,最好建立一个用户只针对某个库有 update、select、delete、insert、drop table、create table等权限,这样就很好避免了数据库用户名和密码被黑客查看后最小损失。
比如下面我们创建一个数据库为db1,同时建立一个用户test1能够访问该数据库。
mysql> create database db1;
mysql> grant select,insert,update,delete,create,drop privileges on db1.* to
test1@localhost
identified by 'admindb';
以上SQL是创建一个数据库db1,同时增加了一个test1用户,口令是admindb,但是它只能从本地连接mysql,对db1库有select,insert,update,delete,create,drop操作权限。
(7) 限制一般用户浏览其他用户数据库
如果有多个数据库,每个数据库有一个用户,那么必须限制用户浏览其他数据库内容,可以在启动MySQL服务器时加--skip-show-database 启动参数就能够达到目的。
( 忘记mysql密码的解决办法
如果不慎忘记了MySQL的root密码,我们可以在启动MySQL服务器时加上参数--skip-grant-tables来跳过授权表的验证 (./safe_mysqld --skip-grant-tables &,这样我们就可以直接登陆MySQL服务器,然后再修改root用户的口令,重启MySQL就可以用新口令登陆了。
(9) 数据库文件的安全
我们默认的mysql是安装在/usr/local/mysql目录下的,那么对应的数据库文件就是在/usr/local/mysql/var目录下,那么我们要保证该目录不能让未经授权的用户访问后把数据库打包拷贝走了,所以要限制对该目录的访问。
我们修改该目录的所属用户和组是mysql,同时改变访问权限:
# chown -R mysql.mysql /usr/local/mysql/var
# chmod -R go-rwx /usr/local/mysql/var
(10) 删除历史记录
执行以上的命令会被shell记录在历史文件里,比如bash会写入用户目录的.bash_history文件,如果这些文件不慎被读,那么数据库的密码就会泄漏。用户登陆数据库后执行的SQL命令也会被MySQL记录在用户目录的.mysql_history文件里。如果数据库用户用SQL语句修改了数据库密码,也会因.mysql_history文件而泄漏。所以我们在shell登陆及备份的时候不要在-p后直接加密码,而是在提示后再输入数据库密码。
另外这两个文件我们也应该不让它记录我们的操作,以防万一。
# rm .bash_history .mysql_history
# ln -s /dev/null .bash_history
# ln -s /dev/null .mysql_history
(11) 其他
另外还可以考虑使用chroot等方式来控制mysql的运行目录,更好的控制权限,具体可以参考相关文章。
4. vsFTPd安全设置
vsFTPd是一款非常著名的ftp daemon程序,目前包括Redhat.com在内很多大公司都在使用,它是一款非常安全的程序,因为它的名字就叫:Very Secure FTP Daemon (非常安全的FTP服务器)。
vsftpd设置选项比较多,涉及方方面面,我们下面主要是针对安全方面进行设置。
目前我们的需求就是使用系统帐户同时也作为是我们的FTP帐户来进行我们文件的管理,目前假设我只需要一个帐户来更新我的网站,并且我不希望该帐户能够登陆我们的系统,比如我们的网站的目录是在/usr/www下面,那么我们新建一个用户ftp,它的主目录是/usr/www,并且它的shell是/usr/sbin/nologin,就是没有shell,防止该用户通过ssh等登陆到系统。
下面在进行系统详尽的设置,主要就是针对vsftpd的配置文件vsftpd.conf文件的配置。
(1) 禁止匿名用户访问, 我们不需要什么匿名用户,直接禁止掉:
anonymous_enable=NO
(2) 允许本地用户登陆,因为我们需要使用ftp用户来对我们网站进行管理:
local_enable=YES
(3) 只允许系统中的ftp用户或者某些指定的用户访问ftp,因为系统中帐户众多,不可能让谁都访问。
打开用户文件列表功能:
userlist_enable=YES
只允许用户文件列表中的用户访问ftp:
userlist_deny=NO
用户名文件列表路径:
userlist_file=/etc/vsftpd.user_list
然后在/etc下建立文件 vsftpd.user_list 文件,一行一个,把用户ftp加进去,同时也可以加上你允许访问的系统帐户名。
(4) 禁止某些用户登陆ftp:
am_service_name=vsftpd
指出VSFTPD进行PAM认证时所使用的PAM配置文件名,默认值是vsftpd,默认PAM配置文件是/etc/pam.d/vsftpd。
/etc/vsftpd.ftpusers
VSFTPD禁止列在此文件中的用户登录FTP服务器,用户名是一行一个。这个机制是在/etc/pam.d/vsftpd中默认设置的。
这个功能和(3)里的功能有点类似,他们俩能结合使用,那样就最好了。
(5) 把本地用户锁定在自己的主目录,防止转到其他目录,比如把/etc/passwd给下载了:
chroot_local_users=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
然后在/etc下建立vsftpd.chroot_list文件,里面把我们要限制的本地帐户加进去,一行一个,我们加上ftp,防止它登陆到系统。
(6) 隐藏文件真实的所有用户和组信息,防止黑客拿下ftp后查看更多系统用户信息:
hide_ids=YES
(7) 取消ls -R命令,节省资源,因为使用该命令,在文件列表很多的时候将浪费大量系统资源:
ls_recurse_enable=NO
( 上传文件的默认权限,设置为022:
local_umask=022
如果要覆盖删除等,还要打开:
write_enable=YES
(9) ftp的banner信息,为了防止黑客获取更多服务器的信息,设置该项:
ftpd_banner=banner string
把后面的banner string设为你需要的banner提示信息,为了安全,建议不要暴露关于vsFTPd的任何信息。
另外,如果你的信息比较多的话,可以设置为提示信息是读取一个文件中的信息:
anner_file=/directory/vsftpd_banner_file
(10) 打开日志功能:
xferlog_enable=YES
同时设置日志的目录:
xferlog_file=/var/log/vsftpd.log
启用详细的日志记录格式:
xferlog_enable=YES
(11) 如果打开虚用户功能等,那么建议关闭本地用户登陆:
local_enable=NO
vsFTPd还有很多安全设置,毕竟人家的名字就是:Very Secure FTP Daemon,反正它的溢出漏洞什么的是很少的,如果要更安全,建议按照自己的需要设置vsftpd,设置的好,它绝对是最安全的。

5. SSH安全设置

SSH是一个基于SSL的安全连接远程管理的服务程序,主要出现就是为了解决telnet、rlogin、rsh等程序在程序交互过程中存在明文传输易被监听的问题而产生的,目前基本上是推荐使用ssh来代替telnet、rlogin、rsh等远程管理服务。
h能够直接在windows平台下通过Secure SSH Client等客户端工具进行连接管理,目前最流行的服务器端就是OpenSSH程序,目前最新版本是OpenSSH4.0版,详细可以参考
http://www.openssh.com
网站。
OpenSSH在FreeBSD下已经集成安装了,FreeBSD5.3下的OpenSSH版本是3.8.1,建议ports升级到4.0。
主要的安全配置文件是/etc/ssh/sshd_config文件,我们编辑该文件。
(1) 使用protocol 2代替protocol 1,SSH2更加安全,可以防止攻击者通过修改携带的版本banner来劫持(hijacking)启动会话进程并降低到protocol 1。注释掉protocol 2,1 改用下面语句代替:
rotocol 2
(2) 合理设置最大连接数量, 防止DOS攻击
MaxStartups 5:50:10
(3)关闭X11forwording ,防止会话劫持
X11Forwarding no
(4)建议不使用静态密码,而使用DSA 或RSA KEY,修改如下内容可以关闭使用密码认证:
PasswordAuthentication no
(5)可以限制某个组或光是单个用户访问shell
AllowGroups wheel
或者
AllowUsers heiyeluren
(6) 限制root用户登陆,主要是为了防止暴力破解
PermitRootLogin no
(7) 不允许口令为空的用户登陆
PermitEmptyPasswords no
(使用TCP wrappers来限制一些访问,修改/etc/hosts.allow文件,注释掉"ALL : ALL : allow",增加如下内容:
hd:localhost:allow
hd:friendlcomputer:allow
hd:all : deny
#相关命令:
#chsh -s /sbin/nologin user

四、防火墙的安装和设置

FreeBSD自带有一个基于包过滤的防火墙--ipfw,虽然功能没有专业防火墙那么强大,但是应付一个Web站点的安全还是足够的,所以我们决定选用该防火墙来保护我们的Web服务器。
1. 安装ipfw
IPFW 的主要部分是在内核中运行的, 因此会需要在FreeBSD内核配置文件中添加部分选项。(注意,如果你没有安装FreeBSD核心源代码,是无法进入以下目录的,所以运行之前一定要先安装内核源代码)我们先进入内核配置文件:
# cd /sys/i386/conf
# cp GENERIC ./kernel_fw
打开内核配置文件:
# ee ./kernel_fw
添加四个选项,不需要后面的注释信息:
options IPFIREWALL # 将包过滤部分的代码编译进内核。
options IPFIREWALL_VERBOSE
# 启用通过syslogd记录的日志。如果没有指定这个选项,即使您在过滤规则中指定记录包, 也不会真的记录它们
options IPFIREWALL_VERBOSE_LIMIT=10
# 限制通过 syslogd( 记录的每项包规则的记录条数。在恶劣的环境中如果您想记录防火墙的活动, 而又不想由于 syslog 洪水一般的记录而导致拒绝服务攻击, 那么这个选项将会很有用。
options IPFIREWALL_DEFAULT_TO_ACCEPT
# 这将把默认的规则动作从 ``deny'' 改为 ``allow''。这可以防止在没有配置防火墙之前使用启用过 IPFIREWALL 支持的内核重启时把自己锁在外面。 另外, 如果您经常使用 ipfw( 来解决一些问题时它也非常有用。 尽管如此,在使用时应该小心, 因为这将使防火墙敞开, 并改变它的行为。
编译内核:
# /usr/sbin/config kernel_fw
# cd ../compile/kernel_fw (注意你的版本,如果是低于5.0的版本用../../compile/kernel_fw)
# make depend
# make
# make install
重启系统。注意,我们没有选择options IPFIREWALL_DEFAULT_TO_ACCEPT该选项,就是说默认系统启动后是打开防火墙的,并且防火墙默认是不允许任何连接的(deny from any to any),所以一定要在本地操作,否则你将被“锁在门外”,如果你选择了该选项则可以使用ssh等连接不受影响,不过这相对不安全。
2. 配置ipfw
如果配置普通情况下的规则,使用命令配置的模式:
ipfw的配置命令:ipfw [-N] 命令 [编号] 动作 [log(日志)] 协议 地址 [其它选项]
例如:
# ipfw add allow tcp from any to 10.10.10.1 80 #允许外界访问我的web服务
# ipfw add allow tcp from any to 10.10.10.1 21 #允许外面访问我的ftp服务
# ipfw add allow tcp from any to 10.10.10.1 22 #允许外界访问我的ssh服务
如果使用规则包的形式,那么查看下面内容。
系统启动后,我们还要配置rc.conf文件来运行我们的防火墙:
# ee /etc/rc.conf
加入如下内容:
gateway_enable="YES" # 启动网关
firewall_enable="YES" # 激活firewall防火墙
firewall_script="/etc/rc.firewall" # firewall防火墙的默认脚本
firewall_type="/etc/ipfw.conf" # firewall自定义脚本
firewall_quiet="NO" # 起用脚本时,是否显示规则信息。现在为“NO”假如你的防火墙脚本已经定型,那么就可以把这里设置成“YES”了。
firewall_logging_enable="YES" # 启用firewall的log记录。
设置完成后我们再编辑/etc/syslog.conf文件:
# ee /etc/syslog.conf
加入以下行:
!ipfw
*.*                 /var/log/ipfw.log
现在到了最重要的编辑规则包了:
# ee /etc/ipfw.conf
我们添加一下规则:(注意 10.10.10.1是我们服务器的IP)
######### TCP ##########
add 00001 deny log ip from any to any ipopt rr
add 00002 deny log ip from any to any ipopt ts
add 00003 deny log ip from any to any ipopt ssrr
add 00004 deny log ip from any to any ipopt lsrr
add 00005 deny tcp from any to any in tcpflags syn,fin
# 这5行是过滤各种扫描包
add 10001 allow tcp from any to 10.10.10.1 80 in  # 向整个Internet开放http服务。
add 10002 allow tcp from any to 10.10.10.1 21 in  # 向整个Internet开放ftp服务。
add 10000 allow tcp from 1.2.3.4 to 10.10.10.1 22 in
# 向Internet的xx.xx.xx.xx这个IP开放SSH服务。也就是只信任这个IP的SSH登陆。
# 如果你登陆服务器的IP不固定,那么就要设为:add 10000 allow tcp from any to 10.10.10.1 22 in
add 19997 check-state
add 19998 allow tcp from any to any out keep-state setup
add 19999 allow tcp from any to any out #这三个组合起来是允许内部网络访问出去,如果想服务器自己不和Internet进行tcp连接出去,可以把19997和19998去掉。(不影响Internet对服务器的访问)
########## UDP ##########
add 20001 allow udp from any 53 to 10.10.10.1 # 允许其他DNS服务器的信息进入该服务器,因为自己要进行DNS解析嘛~
add 29999 allow udp from any to any out # 允许自己的UDP包往外发送。
########## ICMP #########
add 30000 allow icmp from any to any icmptypes 3
add 30001 allow icmp from any to any icmptypes 4
add 30002 allow icmp from any to any icmptypes 8 out
add 30003 allow icmp from any to any icmptypes 0 in
add 30004 allow icmp from any to any icmptypes 11 in
#允许自己ping别人的服务器。也允许内部网络用router命令进行路由跟踪。

[ 本帖最后由 gslsok 于 2009-3-9 13:21 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP