apacheのリバースプロキシ+mod_securityでリバースプロキシ型WAFを簡単に作ってみました。

■ネットワーク図


■説明
今回、リバースプロキシ型WAFを作ってみたかったのでapacheに組み込めるmod_securityとapacheで作ってみました。
例えば、これで攻撃者から攻撃を受けたとしてもリバースプロキシのWAFで防御できるためWAFで防御できたものであればバックにあるWebサーバには影響が出ないようになります。

また、初期導入時の事を考えて最初はブロックせず検知のみにします。
# 最初からブロックしてしまうと正規のアクセスであってもWAFのルールにひかかってブロックされてしまうからです。
# そのため、最初は検知のみにして誤検知があった場合はそのルールを外しながらしばらく様子を見ます。

そこで、リアルタイムにログを監視する「swatch」を導入しmod_securityで検知したログはメールで飛ばす事にします。

ちなみに、今回SSLは利用(設定)しません。

■使用OS

CentOS 5.6 64bit
注)OSのインストール方法は、以下アドレスの通りにしています。
http://www.kurobuti.com/linuxserver/index.php?option=com_content&view=artic
le&id=68&Itemid=74


■httpdバージョン
httpd-2.2.17

■mod_securityバージョン
modsecurity-apache_2.5.13

■swatchバージョン
swatch-3.2.3
※最新版は下記URLを参照してください。
http://sourceforge.net/projects/swatch/

■URL
http://www.example.com/

■リバースプロキシサーバ
Host: example
WAN IP: 192.168.0.60
LAN IP: 192.168.1.60

■Webサーバ
Host: example2
LAN IP:192.168.1.71
※Webサーバは構築済みとします。

(1)apacheをインストール
http://www.kurobuti.com/blog/?p=3365
※specファイルを使用してrpmでインストールします。上記URLを参照してください。

(2)apacheの設定

[root@example ~]# cd /etc/httpd/conf
[root@example conf]# mv httpd.conf httpd.conf.bak
[root@example conf]# vi httpd.conf
# ServerRoot
ServerRoot "/etc/httpd"

# Listen Port
Listen 80

# User and Group
User apache
Group apache

# Load Modules
#LoadModule     alias_module /usr/lib64/httpd/modules/mod_alias.so
LoadModule      proxy_module /usr/lib64/httpd/modules/mod_proxy.so
LoadModule      proxy_http_module /usr/lib64/httpd/modules/mod_proxy_http.so
LoadModule      log_config_module /usr/lib64/httpd/modules/mod_log_config.so
LoadModule      authz_host_module /usr/lib64/httpd/modules/mod_authz_host.so

# mod_security
Include conf/mod_security.d/mod_security.conf

<IfModule mod_proxy.c>
 ProxyRequests Off
</IfModule>

<Proxy *>
 Order allow,deny
 Allow from all
</Proxy>

# Log Setting
ErrorLog "logs/error_log"
LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog "logs/access_log" combined

<VirtualHost *:80>
 ServerName www.example.com
 ProxyPass / http://www.example.com/
 ProxyPassReverse / http://www.example.com/
</VirtualHost>

[root@example ~]# vi /etc/hosts
192.168.1.71    www.example.com

(3)mod_securityインストール
http://www.kurobuti.com/blog/?p=3554
※インストール方法は上記URLの(4)までを参照してください。
※ただ、ここで必要なパッケージは以下だけのものです。
[root@example ~]# yum -y install curl curl-devel libxml2 libxml2-devel lua lua-devel

(4)mod_securityの最新版ルールをダウンロード
ルールをダウンロードするのに必要なperlモジュールをCPANからインストールします。
※CPANでproxyを使いたい場合は下記URLを参照してください。
http://www.kurobuti.com/linuxserver/index.php?option=com_content&view
=article&id=41%3Acpanftpproxy&catid=2%3A2010-05-13-11-40-22&Itemid=2

[root@example ~]# cd modsecurity-apache_2.5.13/tools/
[root@example tools]# cpan -i LWP::UserAgent
[root@example tools]# cpan -i LWP::Protocol::https
[root@example tools]# ./rules-updater.pl -rhttp://www.modsecurity.org/autoupdate/repository/ -prules -Smodsecurity-crs

(5)mod_securityの設定
[root@example tools]# cd rules/modsecurity-crs/
[root@example modsecurity-crs]# unzip modsecurity-crs_2.1.2.zip
[root@example modsecurity-crs]# mkdir /etc/httpd/conf/mod_security.d
[root@example modsecurity-crs]# cp -r base_rules/ /etc/httpd/conf/mod_security.d/
[root@example modsecurity-crs]# cp -r optional_rules/ /etc/httpd/conf/mod_security.d/
[root@example modsecurity-crs]# cp modsecurity_crs_10_config.conf.example /etc/httpd/conf/mod_security.d/modsecurity_crs_10_config.conf
[root@example modsecurity-crs]# vi /etc/httpd/conf/mod_security.d/mod_security.conf
# Load File.
LoadFile /usr/lib64/libxml2.so
LoadFile /usr/lib64/liblua-5.1.so

# LoadModule
LoadModule      unique_id_module /usr/lib64/httpd/modules/mod_unique_id.so
LoadModule      security2_module /usr/lib64/httpd/modules/mod_security2.so

# Log File.
SecAuditEngine On
SecAuditLog On
SecAuditLog logs/mod_security_audit.log

<IfModule mod_security2.c>
 Include conf/mod_security.d/base_rules/*.conf
 Include conf/mod_security.d/modsecurity_crs_10_config.conf
</IfModule>

[root@example modsecurity-crs]# vi /etc/httpd/conf/mod_security.d/modsecurity_crs_10_config.conf
#SecRuleEngine DetectionOnly
# ↓ コメントアウト削除
SecRuleEngine DetectionOnly # 検知のみ。ブロックの場合は「ON」にする。

SecRequestBodyAccess On # POSTを解析する。
SecResponseBodyAccess Off # POSTに対する応答を解析しない。

SecDefaultAction "phase:2,deny,log"
# ↓ 変更
SecDefaultAction "phase:2,deny,log,auditlog,status:406"

(6)apacheを起動
[root@example conf]# service httpd start
httpd を起動中:                                            [  OK  ]
[root@example conf]# chkconfig httpd on
適当にリバースプロキシにアクセスして「mod_security_audit.log」にログが出力されているか確認する。
※Webサーバのaccess_logに出力されるソースIPはリバースプロキシのものとなってしまうのでmod_securityインストールページの一番最後にかかれている項目を確認してください。

(7)swatchのダウンロード
[root@example ~]# wget http://sourceforge.net/projects/swatch/files/swatch/3.2.3/swatch-3.2.3.tar.gz/download

(8)swatchのインストール
[root@example ~]# mv swatch-3.2.3.tar.gz /usr/local/src/
[root@example ~]# cd /usr/local/src/
[root@example src]# tar zxvf swatch-3.2.3.tar.gz
[root@example src]# cd swatch-3.2.3
[root@example swatch-3.2.3]# cpan -i Date::Calc
[root@example swatch-3.2.3]# cpan -i Date::Parse
[root@example swatch-3.2.3]# cpan -i Date::Manip
[root@example swatch-3.2.3]# cpan -i File::Tail
[root@example swatch-3.2.3]# cpan -i Time::HiRes
[root@example swatch-3.2.3]# perl Makefile.PL
Looks good
Writing Makefile for swatch
[root@example swatch-3.2.3]# make
[root@example swatch-3.2.3]# make install
※ここでもCPANを使用してperlモジュールをインストールします。

(9)swatchの設定
[root@example ~]# mkdir -p /etc/swatch/log_watch
[root@example ~]# vi /etc/swatch/swatch.conf
# About a setting method of swatch.
#
# The destination of Log watch config.
#  -- /etc/swatch/log_watch
#
# Log watch config file name.
# Example
#  --  /etc/swatch/log_watch/hogehoge.conf
#
# Creating a Form Configuration File.
# Example File
#  -- # vi /etc/swatch/log_watch/hogehoge.conf
#
# The contents of the configuration file
#   # appoint log to watch.
#   # |/var/log/messages # CommentOut and Pipe /Log path/log file.
#
#     watchfor /error/i # Monitoring character string.
#     echo # acction.
#     mail root,subject=example # acction.

# SWATH Log File.
SWATCH_LOG='/var/log/swatch.log'

# Script Directory.
SCRIPT_DIR='/tmp'

# PID Directory.
PID='/var/run'

# Lock File.
LOCK='/var/lock/subsys/swatch'

[root@example ~]# vi /etc/swatch/log_watch/mod_security.conf
# appoint log to watch.
# |/var/log/httpd/mod_security_audit.log

watchfor /Pattern match/i
        echo
        mail root,subject=Detection_notification

[root@example ~]# vi /etc/logrotate.d/swatch
/var/log/swatch.log {
        compress
        delaycompress
        missingok
}

(10)swatchの起動スクリプト作成
[root@example ~]# vi /etc/rc.d/init.d/swatch
#!/bin/sh
#
# swatch
#
# description: swatch start/stop script.
# chkconfig: 2345 90 35
#
# Source function library.
. /etc/rc.d/init.d/functions

CONF=/etc/swatch/swatch.conf
WATCH_CONF=/etc/swatch/log_watch

prog=swatch

# Config File Check.
if [ -f $CONF ] ; then
 . $CONF
else
 exit 1
fi

start () {
        RETVAL=0
        [ -x /usr/local/bin/swatch ] || exit 1
        for LOG_CONF in $( find $WATCH_CONF | grep conf ) ; do
        WATCH_LOG=`grep \| $LOG_CONF | cut -d \| -f 2`
        /usr/local/bin/swatch --config $LOG_CONF --tail-file $WATCH_LOG \
        --script-dir=$SCRIPT_DIR --awk-field-syntax --use-cpan-file-tail \
        --daemon --pid-file $PID/swatch_`find $WATCH_CONF | grep $LOG_CONF | \
        cut -d / -f 5 | awk -F . '{print $1}'`.pid >> $SWATCH_LOG 2>&1
         if [ $? -ne 0 ] ; then
          let RETVAL=RETVAL+1
         fi
        done
        if [ $RETVAL -eq 0 ] ; then
         echo -n $"Starting $prog: " && success
         echo ""
         touch $LOCK
        else
         echo -n $"Starting $prog: " && failure
         echo ""
         exit 1
        fi
        }

stop () {
        RETVAL=0
        for PID_FILE in $( find $PID | grep swatch ) ; do
        [ -f $PID_FILE ] && kill `cat $PID_FILE` > /dev/null 2>&1
        if [ $? -eq 0 ] ; then
         rm $PID_FILE > /dev/null 2>&1
        else
         let RETVAL=RETVAL+1
        fi
        done
         if [ $RETVAL -eq 0 ] ; then
          echo -n $"Stopping $prog: " && success
          echo ""
          rm $LOCK
         else
          echo -n $"Stopping $prog: " && failure
          echo ""
          exit 1
         fi
        }

stats() {
        for PID_FILE in $( find $PID | grep swatch ) ; do
        [ -f $PID_FILE ] && echo `echo $PID_FILE | awk -F / '{print $4}'` `cat $PID_FILE`
        done
        }

case $1 in
        start )
        start ;;

        stop )
        stop ;;

        restart )
        stop ; sleep 1 ; start ;;

        stats )
        stats ;;

        * )
        echo $"Usage: $0 {start|stop|stats}" ;;
esac

(11)swatchを起動
[root@example ~]# chmod +x /etc/rc.d/init.d/swatch
[root@example ~]# service swatch start
swatch を起動中:                                           [  OK  ]
[root@example ~]# chkconfig swatch on
[root@example ~]# ps aux | grep swatch
root     24552  0.0  1.0 102220 10832 ?        Ss   02:52   0:00 /usr/bin/swatch --config /etc/swatch/log_watch/mod_security.conf --tail-file /var/log/httpd/mod_security_audit.log --script-dir=/tmp -

(12)適当な攻撃をしてみて、検知されたメールが送信されるか確認
XSSでもしてみる。
http://www.example.com/?<script>alert</script>

これで、検知されてメールがroot宛てに届くはず。

後は、正規アクセスで引っかかったやつをホワイトリストに設定すれば大丈夫です。
ホワイトリストは参考文献「3」に例が書かれています。

参考文献
1. http://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Main_Page
2. https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set
_Project#tab=Download

3. http://laquan.hostzi.com/techbox/httpd.html
4. http://webos-goodies.jp/archives/51261261.html
5. http://unixlife.jp/unixlife/linux/t-swatch.jsp


4月 30, 2011 at 3:17 am by 黒ぶちメガネ
Category: Apache, Linux, mod_security