接下来就是限制Apache进程访问文件系统了。这使用chroot来实现,由于这不光可以用于Apache还可以由于它的好搭档:Mysql,所以单独提出来,安全加固Mysql的时候可以参考, 一般来讲:chroot就是创建一个新的root目录结构,并且把httpd这个daemon放到这个新的目录结构里面去运行,在它就只有在这个这个新的root目录下面有访问权限了。
我们在 /chroot/httpd 下面来创建这个新的root目录结构:
mkdir -p /chroot/httpd/dev
mkdir -p /chroot/httpd/etc
mkdir -p /chroot/httpd/var/run
mkdir -p /chroot/httpd/usr/lib
mkdir -p /chroot/httpd/usr/libexec
mkdir -p /chroot/httpd/usr/local/apache/bin
mkdir -p /chroot/httpd/usr/local/apache/logs
mkdir -p /chroot/httpd/usr/local/apache/conf
mkdir -p /chroot/httpd/www
上面这些目录的宿主必须为root的,而且访问权限必须设置为0755。接下来我们创建一个新的设备文件: /dev/null:
ls -al /dev/null
crw-rw-rw- 1 root wheel 2, 2 Mar 14 12:53 /dev/null
mknod /chroot/httpd/dev/null c 2 2
chown root:sys /chroot/httpd/dev/null
chmod 666 /chroot/httpd/dev/null
而创建创建日志设备 /chroot/httpd/dev/log应该使用不同的方法,比如在FreeBSD中可以在/etc/rc.conf中添加下面这一行:
syslogd_flags="-l /chroot/httpd/dev/log"
为了使设置生效,需要重新启动系统或者重新启动syslogd daemon。 在其他系统中创建新的日志设备则需要查看syslogd的手册了(man syslogd)。
接下来就是拷贝Apache的主程序:httpd和其他一些它需要用到的库文件到新的root目录树下,为此,我们需要准备一些如下工具,有些是系统相关的,
但是所有需要用到的工具在不同的系统平台都有相应的实现,比如跟踪系统调用和信号在FreeBSD下使用truss、而Linux下则可以使用strace或者ltrace :
| 命令 | 可用性 | 描述 |
| ldd | 所有的*NIX平台 | Lists dynamiic dependencies of executable files or shared libraries |
| ktrace/ktruss/kdump | *BSD | Enables kernal process tracing, Displays kernal trace data |
| sotruss | Solaris | Traces shared library procedure calls |
| strace/ltrace | Linux | Traces system calls and signals |
| strings | All | Finds the printable strings in binary files |
| trace | AIX | Records selected system events |
| trace (freeware) | HP-UX <10.20 | Print system call and kernal traces of processes |
| truss | FreeBSD, Solaris, AIX 5L, SCO Unixware | Traces system calls and signals |
| tusc (freeware) | HP-UX>11 | Traces the system calls a process invokes in HP-UX 11 |
以ldd, strings 和 truss 为例:
localhost# ldd /usr/local/apache/bin/httpd
/usr/local/apache/bin/httpd:
libcrypt.so.2 => /usr/lib/libcrypt.so.2 (0x280bd000)
libc.so.4 => /usr/lib/libc.so.4 (0x280d6000)
localhost# strings /usr/local/apache/bin/httpd | grep lib
/usr/libexec/ld-elf.so.1
libcrypt.so.2
libc.so.4
localhost# truss /usr/local/apache/bin/httpd | grep open
(...)
open("/var/run/ld-elf.so.hints",0,00) = 3 (0x3)
open("/usr/lib/libcrypt.so.2",0,027757775370) = 3 (0x3)
open("/usr/lib/libc.so.4",0,027757775370) = 3 (0x3)
open("/etc/spwd.db",0,00) = 3 (0x3)
open("/etc/group",0,0666) = 3 (0x3)
open("/usr/local/apache/conf/httpd.conf",0,0666) = 3 (0x3)
(...)
上面这些命令不光适用于httpdm, 也适用于其他的相互依赖的库文件。所以在FreeBSD下下面这些文件需要拷到新的root目录结构下:
cp /usr/local/apache/bin/httpd /chroot/httpd/usr/local/apache/bin/
cp /var/run/ld-elf.so.hints /chroot/httpd/var/run/
cp /usr/lib/libcrypt.so.2 /chroot/httpd/usr/lib/
cp /usr/lib/libc.so.4 /chroot/httpd/usr/lib/
cp /usr/libexec/ld-elf.so.1 /chroot/httpd/usr/libexec/
利用truss我们还可以发现一下这些配置文件也必须拷到新的root目录树结构下:
cp /etc/hosts /chroot/httpd/etc/
cp /etc/host.conf /chroot/httpd/etc/
cp /etc/resolv.conf /chroot/httpd/etc/
cp /etc/group /chroot/httpd/etc/
cp /etc/master.passwd /chroot/httpd/etc/passwords
cp /usr/local/apache/conf/mime.types /chroot/httpd/usr/local/ \
apache/conf/
需要提醒的是 /chroot/httpd/etc/passwords文件中除了"nobody" and "apache"以外,都必须删除. 类似的/chroot/httpd/etc/group中也需要删除除"nobody" and "apache"以外的组。接下来,使用如下命令建立新的口令数据库:
cd /chroot/httpd/etc
pwd_mkdb -d /chroot/httpd/etc passwords
rm -rf /chroot/httpd/etc/master.passwd
好了,接下来我们就可以测试一下httpd在新的root下能否正确运行。所以需要拷贝Apache的默认配置文件和index.html:
cp /usr/local/apache/conf/httpd.conf /chroot/httpd/usr/local/apache/\
conf/
cp /usr/local/apache/htdocs/index.html.en /chroot/httpd/www/
然后调整一下httpd.conf里面的DocumentRoot指令(编辑 /chroot/httpd/usr/local/apache/conf/httpd.conf):
DocumentRoot "/www"
启动Apache:
chroot /chroot/httpd /usr/local/apache/bin/httpd
如果启动失败可以查看一下apache的日志:/chroot/httpd/usr/local/apache/logs. 另外也可以使用truss跟踪一下:
truss chroot /chroot/httpd /usr/local/apache/bin/httpd
它会报告问题出在什么地方的,却了什么文件啊?之类的问题,很快就可以解决问题,让你看到index.html。
OK, 我们开始正式配置我们的Apache了,这也是最后一步:
配置Apache
要安全嘛肯定不能偷懒,首先是删除原始的/chroot/httpd/usr/local/apache/conf/httpd.conf然后创建一个新的/chroot/httpd/usr/local/apache/conf/httpd.conf,内容大致如下:
# =================================================
# Basic settings
# =================================================
ServerType standalone
ServerRoot "/usr/local/apache"
PidFile /usr/local/apache/logs/httpd.pid
ScoreBoardFile /usr/local/apache/logs/httpd.scoreboard
ResourceConfig /dev/null
AccessConfig /dev/null
# =================================================
# Performance settings
# =================================================
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15
MinSpareServers 5
MaxSpareServers 10
StartServers 5
MaxClients 150
MaxRequestsPerChild 0
# =================================================
# Apache's modules
# =================================================
ClearModuleList
AddModule mod_log_config.c
AddModule mod_mime.c
AddModule mod_dir.c
AddModule mod_access.c
AddModule mod_auth.c
# =================================================
# General settings
# =================================================
Port 80
User apache
Group apache
ServerAdmin Webmaster@www.hackgou.lab
UseCanonicalName Off
ServerSignature Off
HostnameLookups Off
ServerTokens Prod
DirectoryIndex index.html
DocumentRoot "/www/vhosts"
# =================================================
# Access control
# =================================================
Options None
AllowOverride None
Order deny,allow
Deny from all
Order allow,deny
Allow from all
Order allow,deny
Allow from all
# =================================================
# MIME encoding
# =================================================
TypesConfig /usr/local/apache/conf/mime.types
DefaultType text/plain
AddEncoding x-compress Z
AddEncoding x-gzip gz tgz
AddType application/x-tar .tgz
# =================================================
# Logs
# =================================================
LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
ErrorLog /usr/local/apache/logs/error_log
CustomLog /usr/local/apache/logs/access_log combined
# =================================================
# Virtual hosts
# =================================================
NameVirtualHost *
DocumentRoot "/www/vhosts/www.hackgou.lab"
ServerName "www.hackgou.lab"
ServerAlias "www.hackgou.lab"
ErrorLog logs/www.hackgou.lab/error_log
CustomLog logs/www.hackgou.lab/access_log combined
DocumentRoot "/www/vhosts/www.test.lab"
ServerName "www.test.lab"
ErrorLog logs/www.test.lab/error_log
CustomLog logs/www.test.lab/access_log combined
上面的配置命令实现了功能需求和安全要求。在配置中,有两个虚拟主机:
- www.hackgou.lab
- www.test.lab
上面这些站点看起来的结构如下:
- /chroot/httpd/www/vhosts/www.hackgou.lab
- /chroot/httpd/www/vhosts/www.test.lab
每个站点有自己的日志:
- /chroot/httpd/usr/local/apache/logs/www.ebank.lab
- /chroot/httpd/usr/local/apache/logs/www.test.lab
当然这些目录必须在Apache第一次执行之前创建好。上面这些目录的宿主也应该为:root:sys, 访问权限也应该设为:0755。
如果对照Apache的默认设置,我们的配置有如下不同:
最后一步:
创建启动脚本"apache.sh", 方便系统管理,如下:
#!/bin/sh
CHROOT=/chroot/httpd/
HTTPD=/usr/local/apache/bin/httpd
PIDFILE=/usr/local/apache/logs/httpd.pid
echo -n " apache"
case "$1" in
start)
/usr/sbin/chroot $CHROOT $HTTPD
;;
stop)
kill `cat ${CHROOT}/${PIDFILE}`
;;
*)
echo ""
echo "Usage: `basename $0` {start|stop}" >&2
exit 64
;;
esac
exit 0
然后把这个脚本拷到正确的位置 (就看你是那个 UNIX系统了), FreeBSD下当然就是 /usr/local/etc/rc.d 目录下了。
后记
由于没有PHP、Perl、CGI以及mod_proxy、mod_ssl、mod_rewrite等模块,无法实现动态交互、代理、ssl、URL重写等功能,但是通过上面这些方法就能够使Apache的安全级别达到一个很高的水平了,是远远超过任何一个二进制预编译版本了。