ModSecurity/NginxによるWAF構築  

いまさら感はありますがWebApplicationFireWall(ModSecurity)についての記事です。
WAFの動作検証ができるようWebgoatを起動させる構成にしています。

WAF動作検証が目的となっている為、本来すべきOSセキュリティ設定などは割と適当になっています。本番での運用を検討される方は、CIS Benchmarkなどを参考にあるべき設定をしてください。　
[CIS Benchmark](https://www.cisecurity.org/cis-benchmarks/)

## 1. 環境  

* OS : CentOS7.9
* Kernel: 3.10.0-1160.49.1.el7.x86_64
* ModSecruity： v3.0.6-11-g76ce673
* Nginx: 1.18.0
* Tomcat: 7.0.76-16.el7_9
* webgoat： 7.0.1 

## 2. WebGoatインストール

WebGoatインストール前にSELinux無効化とfirewalldのポート許可設定を追加して
OSをリスタートします。#本番環境で使う場合はSELinuxは有効化してください!!  

```bash
yum -y update
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload
shutdown -r now
```

開発用パッケージをインストールします。  

```bash
yum groupinstall 'Development Tools' -y
yum -y install vim wget git policycoreutils-python libtool epel-release.noarch
```

Tomcatをインストールします。

```bash
yum -y install tomcat
```

webgoat-containerをダウンロードしてwebapps配下に移動します。

```bash
wget https://github.com/WebGoat/WebGoat/releases/download/7.0.1/webgoat-container-7.0.1.war
mv webgoat-container-7.0.1.war /usr/share/tomcat/webapps/webgoat.war
systemctl start tomcat
```

[http://*IPaddress*:8080/webgoat] で下記画面がでればWebgoatはOKです。
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/e7ab1db5-ab88-49c9-8180-be3ccda4374f.png">


## 3. ModSecurityのインストール

ModSecurityインストールに必要となるパッケージを入れます。

```bash
yum -y install gcc-c++ flex bison yajl yajl-devel curl-devel curl GeoIP-devel doxygen zlib-devel pcre-devel lmdb lmdb-devel libxml2 libxml2-devel ssdeep ssdeep-devel lua lua-devel openssl openssl-devel
```

ModSecurityのソースをGithubよりダウンロードしてインストールします。

```bash
cd /opt/
git clone https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git checkout -b v3/master origin/v3/master
sh build.sh
git submodule init
git submodule update
./configure --with-lmdb --with-yajl
make
make install
```

| オプション | 説明 |
|:-|:-|
|--with-yajl|JSONライブラリであるYAILを有効にする。ModSecrutiyでは監査LOGをJSON形式で保存する場合必須となるコンパイルオプション|
|-with-geoip|GEOIPを有効にする（ModSecrutiy v2）|
|--withmaxmind|GEOIPを有効にする（ModSecrutiy v3）|
|--withssdeep|Fuzzy Hashingによるマルウェア検出を有効にする|
|--with-lmdb|ModSecurityのcollection保存⽤としてLMDBを有効にする|
|--with-lua|luaを有効にする。外部スクリプトを実⾏する際、Luaで書かれたスクリプトを実⾏する事を推奨されている|
|--with-libxml|XMLを解析・操作するライブラリを有効にする|
|--with-pcre|Perl 5 互換の正規表現をC⾔語で実装したライブラリを有効にする|

## 4. Nginxインストール

Nginx用のユーザを作成します。

```bash
groupadd -g 1001 nginx
useradd -u 1001 -g 1001 -d /var/lib/nginx -s /sbin/nologin -c "Nginx Web Server" nginx
```

Nginxをインストールします。

```bash
cd ../
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar zxvf nginx-1.18.0.tar.gz
cd nginx-1.18.0
./configure --prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/module \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/run/lock/subsys/nginx \
--user=nginx \
--group=nginx \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-threads \
--add-dynamic-module=../ModSecurity-nginx \
--with-pcre \
--with-pcre-jit

make 
make install
```

## 5. Nginx起動前Configファイル作成

```bash
mkdir /etc/nginx/conf.d
mkdir /etc/nginx/modules
mkdir /etc/nginx/modsecurity
cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules
cp ../ModSecurity/modsecurity.conf-recommended /etc/nginx/modsecurity/modsecurity.conf
cp ../ModSecurity/unicode.mapping /etc/nginx/modsecurity/
```

## 6. CoreRuleSet(CRS)のインストール

次にWAFのシグネチャにあたるCRSをダウンロードし、/etc/nginx/modsecurity 配下にコピーします。

```bash
cd ..
git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git
mv owasp-modsecurity-crs/crs-setup.conf.example ./owasp-modsecurity-crs/crs-setup.conf  
cp -pr owasp-modsecurity-crs /etc/nginx/modsecurity/
```

Nginxで読み込ませるModSecurityのconfファイルを作成します。

```bash
vim /etc/nginx/modsecurity/modsec_includes.conf
include modsecurity.conf
include /etc/nginx/modsecurity/owasp-modsecurity-crs/crs-setup.conf
include /etc/nginx/modsecurity/owasp-modsecurity-crs/rules/*.conf
:wq
```

## 7. Nginx設定ファイル修正

```bash
vim /etc/nginx/nginx.conf
load_module modules/ngx_http_modsecurity_module.so; #ファイルの一番上に追記
location / {
root html;
index index.html index.htm;
modsecurity on; #modsecurity有効化
modsecurity_rules_file /etc/nginx/modsecurity/modsec_includes.conf; #Configファイルを指定
proxy_pass http://localhost:8080/; #tomcatへのプロキシ設定
:wq
```

## 8. Nginx起動スクリプト作成

```bash
vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
:wq
```

## 9. 権限変更&Nginxスタート
```bash
vim /etc/nginx/modsecurity/owasp-modsecurity-crs/rules/local-001.conf
SecRuleRemoveById 920350 #ipでアクセスしてもWAFルールで検知されないよう除外しておく
:wq
sed -i 's/SecDefaultAction "phase:1,log,auditlog,pass"/#SecDefaultAction "phase:1,log,auditlog,pass"/g' /etc/nginx/modsecurity/owasp-modsecurity-crs/crs-setup.conf 
sed -i 's/SecDefaultAction "phase:2,log,auditlog,pass"/#SecDefaultAction "phase:2,log,auditlog,pass"/g' /etc/nginx/modsecurity/owasp-modsecurity-crs/crs-setup.conf 
sed -i 's/# SecDefaultAction "phase:1,log,auditlog,deny,status:403"/SecDefaultAction "phase:1,log,auditlog,deny,status:403"/g' /etc/nginx/modsecurity/owasp-modsecurity-crs/crs-setup.conf 
sed -i 's/# SecDefaultAction "phase:2,log,auditlog,deny,status:403"/SecDefaultAction "phase:2,log,auditlog,deny,status:403"/g' /etc/nginx/modsecurity/owasp-modsecurity-crs/crs-setup.conf 
cd /etc
chown -R nginx:nginx nginx
nginx -t 
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful 
systemctl start nginx 
chown root:nginx /var/log/modsec_audit.log 
systemctl restart nginx  
```

## 10. 動作確認
[http://*IPaddress*/webgoat] にアクセスしてUsernameに「'or 1=1」と入力します。
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/096c49a1-1d34-1aa3-29c1-cc6c87ddb752.png">

/var/log/modsec_audit.logを開いて下記のようなログが出力されていれば攻撃を検知しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/0accd7d5-ddcb-8606-a728-082c48039689.png)

※ModSecurityはデフォオルトが検知モードになっていますので、ブロックモードに 
　変更する場合は/etc/nginx/modsecurity/modsecurity.confのSecRuleEngineをDetectionOnly 
　からOnに変更します。


WebGoatはWebアプリケーションの脆弱性を学習・実践する目的で作成されたものなので 
それがModSecurityで防がれている様子など別の記事で書きたいと思います。