本文作者初入安全行业,入职行业某云安全公司,得到了职业导师的指点,从基础入手学习网络安全,此文章是作者学习web中间件的apache笔记,从搭建—安全配置—日志分析进行深入的分析和学习,仅以此文分享给更多的同样在路上的安全行业从业者

Web中间件学习篇

本篇主要从IIS、Apache、Nginx、Tomcat四种常见中间件的Apache入手,介绍相关安全知识,遵循“中间件简介→如何搭建网站→安全配置分析→安全日志分析”的顺序进行学习,旨在梳理常见Web中间件的知识点,为Web安全学习打好基础。

多提一下:原本我写作的顺序是IIS、Apache、Nginx、Tomcat但是发稿的顺序出了点问题,现在应该是Nginx、IIS、Apache、Tomcat的顺序了,请见谅。同时写作的内容由于阅历和时间有限无法深入展开,如果各位对其中的内容有不同的看法欢迎留言交流~

Apache篇

作者:古月蓝旻@安全之光

Apache简介

Apache起初由伊利诺伊大学香槟分校的国家超级电脑应用中心(NCSA)开发。此后,Apache Httpd被
开放源代码团体的成员不断的发展和加强。Apache Http网站服务器拥有牢靠可信的美誉,已经在
全球超半数的网站中被使用-特别是几乎所有最热门和访问量最大的网站。比方说,维基百科网站服务器
就是使用Apache的。
刚开始发展时,Apache只是Netscape网页服务器(现在是Sun ONE)之外的开放源代码选择之一。
它开始在功能和速度超越其他基于Unix的HTTP服务器。到了Apache 2.x的时代,实际效率又比
Apache 1.x更快,2.x比1.x能同时服务更多的网页连接数。
1996年4月以来,Apache一直是Internet上最流行的HTTP服务器:1999年5月它在57%的网页服务器上
运行,到了2005年7月这个比例上升到了69%。在2005年11月最风光的时候达到接近70%的市占率,
不过在部分拥有大量域名的主机域名商转换为微软IIS平台后,Apache市占率近年来呈现些微下滑。
同时搜索引擎巨擘Google自己的网页服务器平台GWS推出后(也可说是一种修改版的Apache),再加上
nginx、Lighttpd等轻量化网页服务器软件在市场上有一些能见度,这些因素都反应在整体网页服务
器市占率的消长,Apache的市占率就随之滑落。
根据Netcraft在2009年12月的最新统计数据,Apache的市占率已经降为53.67%,IIS降为18.26%,
谷歌网页服务器13.53%,nginx 8.75%。
尽管如此,Apache及其各种分支版本仍旧是当前互联网市场上,市占率最高的网页服务器软件

Apache站点搭建

Apache的站点搭建相对于IIS而言还是比较简单的,无需过多的配置,只需要安装相应的软件和插件即可。以配置php站点为例,主要分为以下几步:

  1. 安装httpd服务;
  2. 安装Mysql、php、配置phpmyadmin;
  3. 部署php站点;

下面开始详细介绍如何搭建一个完整的Apache站点

环境介绍

操作系统:CentOS release 6.5 (Final)
Apache版本:httpd-2.2.15-60.el6.centos.4.x86_64
站点类型:php

搭建步骤

安装httpd服务

整个安装过程还是非常轻松的

yum -y install httpd
service httpd start

有必要的话可以设置其开机启动,顺便安装一些apache拓展

chkconfig httpd on
 yum -y install httpd-manual mod_ssl mod_perl mod_auth_mysql

此时去访问localhost或者127.0.0.1或者本机访问本机ip就可以看见熟悉的apache界面

但是由于iptables的缘故,其它主机还是无法访问的,此时有两种方法可以解决:

方法一
iptables -F   //直接清除iptables规则,本次开机有效,过于简单粗暴,不推荐
方法二
/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT  //添加开启80端口规则
/etc/rc.d/init.d/iptables save  //保存配置
/etc/rc.d/init.d/iptables restart   //重启iptables
/etc/init.d/iptables status   //查看开放的端口,出现80
顺便一提,想开启ssh服务也可将22端口如上述方法设置规则

此时其它主机已经可以正常访问

安装Mysql、php、配置phpmyadmin

yum -y install mysql mysql-server mysql-devel   //安装mysql和其相关拓展
chkconfig mysqld on  //设置其开机启动
service mysqld start   //启动mysqld服务
/usr/bin/mysql_secure_installation  //设置mysql的一些安全配置
这一步还是很重要的,主要是设置mysql的root密码,是否需要删除匿名账号等等,根据实际需要设置

此时我们可以登录一下mysql

 yum -y install php   //安装php
 yum -y install php-mysql gd php-gd gd-devel php-xml php-common 
 yum -y install php-mbstring php-ldap php-pear php-xmlrpc php-imap  php-mcrypt
 //安装php常用拓展
 service httpd restart   //重启httpd服务,这一步非常重要

完成之后可以简单测试一下,在/var/www/html目录下新建phpinfo.php文件,让其输出一下相关信息

下一步就是安装phpmyadmin,这个其实是可选步骤,只是为了方便图形化管理mysql,下载官网:phpmyadmin下载官网

在官网下载了phpMyAdmin-4.0.10.20-all-languages.tar.gz

下载的是老版本,这个是由于我安装的php版本为5.3.3,低于5.5,一开始下载的4.7.3的版本配置了半天还是显示403比较无语,老版本不会出问题

tar -xvzf phpMyAdmin-4.0.10.20-all-languages.tar.gz
mv phpMyAdmin-4.0.10.20-all-languages /var/www/html/phpmyadmin
cd /var/www/html/phpmyadmin
cp libraries/config.default.php config.inc.php

然后修改一下相关配置vi config.inc.php,一般改这些

$cfg['PmaAbsoluteUri'] = '';这里填写 phpMyAdmin 的访问网址。

$cfg['Servers'][$i]['host'] = 'localhost'; // MySQL hostname or IP address

$cfg['Servers'][$i]['port'] = ''; // MySQL port - leave blank for default port

$cfg['Servers'][$i]['user'] = 'root'; // 填写 MySQL 访问 phpMyAdmin 使用的 MySQL 用户名,默认为 root。

$cfg['Servers'][$i]['password'] = ''; // 填写对应上述 MySQL 用户名的密码。

$cfg['blowfish_secret'] = '1qaz2wsx3edc';//随意,长度不要太短

实际过程中其实我也只是修改了password一处为我的mysql密码,blowfish_secret其实也可以修改,否则登录后会给个警告,但是不影响使用最后重启一下httpd服务 service httpd restart打开浏览器访问http://localhost/phpmyadmin或者http://ip/phpmyadmin即可

部署php站点

这一步相对而言比较简单,我直接使用了我毕设时制作的php源码包,修改了一下其中的db_config.php,把root密码改成目前设置的,最后访问一下login.php,非常完美

然后登录一下,结果。。。

写了一个小的脚本看一下报的什么错

<?php
     @ $mysqli = new mysqli($dbConf[host],$dbConf[user],
                $dbConf[password],$dbConf[dbName],$dbConf[port]);
        if ($mysqli->connect_errno) {
         echo "不能连接到数据库<br/>";
         echo mysqli_connect_error($mysqli);
        return;
        }
        else {echo "mission success!";}
?>

显示Access denied for user ‘root’@'localhost’ (using password: NO)这个问题非常奇怪,找了半天全是关于终端登录mysql时出现这种问题,看来问题还是出现在我写的db_config.php上,最后根据经验将host从127.0.0.1改成localhost居然好了

仔细查了这个问题发现对于mysql和php这两者还真的不一样,甚至连接方式都不相同

简而言之

当主机填写为localhost时mysql会采用 unix domain socket连接
当主机填写为127.0.0.1时mysql会采用tcp方式连接
这是linux套接字网络的特性,win平台不会有这个问题

Apache日志分析

Apache日志主要分为两类:error_logaccess_log ,实际排查过程中更常用的是error_log

关于Apache日志文件的位置,详细信息可以查看Apache的配置文件,但是由于Linux发行版的差异和安装方式的不同,其配置文件也不尽相同,下面开始分别介绍:

Apache日志(Debian家族)

常用于Debian,Ubuntu或Linux Mint
测试系统:Ubuntu 16.04 LTS
使用apt-get方式安装 apache2 2.4.18-2ubuntu3.3
此时的配置文件名称为apache2.conf

一般情况下该配置文件路径为/etc/apache2/apache2.conf,如果使用编译安装或者dpkg等方式安装的话路径可能会有不同,此时一般建议使用locate搜索一下apache2.conf

updatedb
locate apache2.conf

日志文件信息就写在该配置文件中

其中使用了变量APACHE_LOG_DIR指代了前面的路径,而$APACHE_LOG_DIR到底代表什么,其实这个值是环境变量,一切和apache2环境变量有关的值全在/etc/apache2/envvars中,env为环境缩写,vars为变量缩写,打开后可以发现该值为/var/log/apache2/

拼接一下,完整的error_log路径为

/var/log/apache2/error.log

查看一下/var/log/apache2下的文件,包括access.log(访问日志)、error.log(错误日志)、other_vhosts_access.log(虚拟主机日志)

access.log

我们可以打开access.log文件看一下其中的内容

下面我们详细解释一下吧,首先这个日志格式,仍然来源于配置文件apache2.conf,其中有关于LogFormat的定义

第一个可以不用管它,它是虚拟主机的日志文件格式,本篇不做讨论

LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common

第二个和第三个分别为组合日志格式(Combined Log Format)和通用日志格式(Common Log Format),本系统中由于Combined在Common之前,因此access_log日志按照Combined Log Format方式记录,解释下各个字段的含义,以下面一行为例:

127.0.0.1 – - [24/May/2017:10:31:39 +0800] “GET / HTTP/1.1″ 200 3525 “-” “Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0″

对应

LogFormat “%h %l %u %t \”%r\” %>s %O \”%{Referer}i\” \”%{User-Agent}i\”" combined

其中:

%h 远端主机 对应127.0.0.1
%l 远端登录名(由identd而来),除非IdentityCheck设为"On",否则将得到一个"-"
%u 远程用户名(根据验证信息而来),若不存在得到一个"-"
%t 时间,用普通日志时间格式(标准英语格式) 对应[24/May/2017:10:31:39 +0800]
\"%r\" 请求头的第一行,\用于转移双引号,对应 "GET / HTTP/1.1"
%>s  该请求最后的状态码,对应200
%O 发送的字节数,包括请求头的数据,并且不能为零,对应3525
\"%{Referer}i\"该请求来源页面,此处对应"-"
\"%{User-Agent}i\"该请求使用的浏览器信息,对应"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; 
                  rv:53.0) Gecko/20100101 Firefox/53.0"

第四个和第五个类似,补充一条

%U 请求的URL路径,不包含查询字符串。

关于Apache日志完整字段内容可以参考以下文章apache日志 LogFormat参数说明

error.log

相对于access.log日志文件,apache的error.log要简单一些,首先在apache2.conf文件中定义了其路径(ErrorLog)及记录等级(LogLevel)

类似于Linux的syslog,只记录等级在配置文件中规定及以上的信息,如上图所示,error.log中只记录等级在warn以上的信息,以下为错误信息等级排序:

查看一下error.log中到底记录了什么吧

其实这张图不是特别好,居然记录的全是notice的信息,而notice的等级在warn之下,为什么会被记录?

注意:当错误日志是一个单独分开的正式文件的时候(如本例中就是单独的/var/log/apache2/error.log文件),notice级别的消息总是会被记录下来,而不能被屏蔽。但是,当使用syslog来记录时就没有这个问题。

以上图片还表明了apache错误日志记录的格式为

[日期和时间]   [错误等级]   错误消息

关于日志文件的更多内容可以查阅该网站Apache的日志文件

Apache日志(RedHat家族)

常用于CentOS,Fedora或RHEL 测试系统:CentOS release 6.5 使用yum方式安装 Apache/2.2.15 (Unix) 此时的配置文件名称为httpd.conf

一般情况下该配置文件路径为/etc/httpd/conf/httpd.conf,如果使用编译安装或者rpm等方式安装的话路径可能会有不同,此时一般建议使用locate搜索一下httpd.conf,还有更简便的方法,后面会介绍

updatedb
locate httpd.conf

日志文件信息就写在该配置文件中

典型的相对路径的写法,还要找一下路径的起始位置,可以搜索一下ServerRoot

拼接一下,完整的error_log路径为

/etc/httpd/logs/error.log

与此同时,我们还可以在/var/log/httpd/目录下找到相同的error.log文件,这是怎么回事呢?

显而易见,/etc/httpd/logs/目录是/var/log/httpd的一个软链接

更简单的查看方法,可以使用以下命令

httpd -V

指出了httpd的根目录为/etc/httpd,错误日志目录为/etc/httpd/+logs/error_log,配置文件目录为/etc/httpd/+conf/httpd.conf

查看一下/etc/httpd/logs下的文件,包括access.log(访问日志)、error.log(错误日志)、ssl_access_log(https访问日志)、ssl_error_log(https错误日志)、ssl_request_log(https请求日志)

access.log

我们可以打开access.log文件看一下其中的内容

下面我们详细解释一下吧,首先这个日志格式,仍然来源于配置文件httpd.conf,其中有关于LogFormat的定义

这个和Debian家族的apache2.conf中的定义是一样的,此处就不详细展开了,有一点不同之处:httpd.conf中的access.log指定了日志格式为Combined Log Format,而apache2.conf中并未提及,只是按照顺序选择了Combined Log Format

error.log

这个和Debian家族的error.log基本上是相同的,httpd中同样记录了LogLevel为Warn

注意:当错误日志是一个单独分开的正式文件的时候(如本例中就是单独的/var/log/apache2/error.log文件),notice级别的消息总是会被记录下来,而不能被屏蔽。但是,当使用syslog来记录时就没有这个问题。

以上图片还表明了apache错误日志记录的格式为

[日期和时间]   [错误等级]   错误消息

查看该日志我们可以发现一个问题:php的access.log和error.log直接记录在了httpd的日志路径下,难道php的日志不会记录在自己的相关目录下吗?

这个问题可以在/etc/php.ini(php配置文件默认路径)中得到答案

php的错误日志文件可以自定义输出路径,也可以输出到syslog中,但是在该文件中均被分号注释了,因此日志文件默认通过web中间件进行存储

Apache日志分析Web攻击行为

Apache日志有一个重要作用就是分析Web攻击行为

sql注入攻击

下面使用Apache日志分析sqlmap对网站进行sql注入攻击。

首先还是找一处注入点

打开access.log文件可以看见非常多的访问记录,包括IP、访问时间、UA以及sqlmap的攻击payload等信息

xss攻击

下面使用Apache日志分析burp suite对网站进行xss跨站攻击。

首先使用burp suite随意拦截一处网址url,并在dcbid字段标记,使用xss-fuzzing攻击

由于这个站点设置过XSS过滤,因此以上payload没有成功

但是查看日志文件,同样可以看见大量的xss攻击记录

post方式访问

Apache的日志能否记录POST请求数据呢?我们使用burp suite将GET请求更改为POST,并添加内容为hello qingteng~~

去日志文件中查看,可以发现对于此次的POST 请求,日志中是有记录的,但并未记录POST提交的内容

那么apache中如何让日志文件记录POST提交的信息呢?

  1. apache加载dumpio模块。这个需要在httpd.conf文件中进行设置,apache默认不启用该模块,找到下面一行,去掉最前方的#号

     # LoadModule dumpio_module modules/mod_dumpio.so`
    

  1. 配置日志告警级别。将原先的LogLevel注释掉,添加DumpIO模块的记录

    LogLevel debug

    DumpIOInput On

    DumpIOOutput On

    DumpIOLogLevel debug

3.重启apache

测试一下,还是POST方式传入hello qingteng~~,此时在error.log(特别注意不是access.log)中,我们可以看见POST传入的值

补充知识点

1. 如何修改apache默认端口号?

这个问题非常简单,打开httpd.conf文件,

找到Listen 80 一行,将80修改为想要设置的端口号,保存,重启httpd即可

测试时在本机浏览器输入http://127.0.0.1:新端口号 即可

注:外网主机此时可能无法通过http://IP:新端口号 方式访问,记得修改iptables,添加新端口号规则。

2. 以root身份启动apache,该服务以什么用户运行?

使用ps aux|grep httpd|grep -v grep查看一下

第一列中既有root,又有apache,其中第一行为httpd主进程,自第二行起为httpd子进程,这个是由于apache默认端口为80(http)和443(https),而Linux中启动小于1024的端口,必须使用root权限。

如果配置文件中的Listen directive设置了默认端口为80(或者是其它的值,但要小于1024),接下来apache httpd就需要root权限来启动apache,这是因为在将应用进程绑定在(1-1024)这个保留端口范围内的时候,需要root权限。

当 server一旦启动并且执行了些许初步动作,比如打开log日志文件,接下来server会装载执行指定数目的child processes,这些process是用来复杂监听端口,处理来自client的请求并且返回响应。

而主httpd process仍然以root权限继续运行,但是这些child processes会以较低的权限运行,而这些行为都可以通过选择Multi-processing Module来进行控制。

关于apache进程的详细内容可参见此文:apache之httpd启动、终止、重启小结

作者:安全之光