NginxのWAFモジュールのNaxsi(naxsi-0.54)をインストールしてみた

NginxのWAFモジュールのNaxsiがバージョンアップしていたので、そのインストールと設定手順をまとめました。

大きく変わった箇所として、ホワイトリストの自動生成を行う[nx_tool]が[nxapi]と名前を変え、ホワイトリスト生成のための統計データの保存先がSQLiteからElasticSeaechへと変更されています。

では、さっそく。

# 準備
## Nginxとnaxsiのダウンロード

```bash:コマンド
cd /usr/local/src/
wget https://github.com/nbs-system/naxsi/archive/0.54.tar.gz
tar zxvf naxsi-0.54.tgz

https://nginx.org/download/nginx-1.10.1.tar.gz
tar zxvf　nginx-1.10.1.tar.gz
```

## NginxにNaxsiモジュールを追加してインストール
Nginxのconfigureオプションはお好みで

```bash:コマンド
cd /uer/local/src/nginx-1.10.1/
./configure --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_stub_status_module --add-module=../naxsi-0.54/naxsi_src/

make && maike install
```

## ElasticSearchの用意
naxsi-0.54では、ElasticSearchのVersion1系を利用します。
Elasticのダウンロードページからは、1系最新のダウンロードページにたどり着けないので
下記のURLからダウンロードします。
```
https://www.elastic.co/guide/en/elasticsearch/reference/1.7/_installation.html
```

## ElasticSearchのインストールと起動
```
cd /usr/local/src/
wget https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.7.5.tar.gz

tar -xvf elasticsearch-1.7.5.tar.gz

cd elasticsearch-1.7.5/bin
./elasticsearch
```

## ElasticSearchの動作確認とNxapi用のIndexの作成
```
curl -XGET http://localhost:9200/

curl -XPUT 'http://localhost:9200/nxapi/'
```

# Naxsiのセットアップ

## Naxsiに付属しているディフォルトルールの配置
```bash:コマンド
cp -rp /usr/local/src/naxsi-0.54/naxsi_config/naxsi_core.rules /usr/local/nginx/conf/
```

## nxapiをコピー
```bash:コマンド
cp -rp /usr/local/src/naxsi-0.54/nxapi/ /usr/local/nginx/
``` 

## nxapiの設定
```nginx:/usr/local/nginx/nxapi/nxapi.json
{
# ElasticSearchの設定
"elastic" : {
 "host" : "127.0.0.1:9200",
 "index" : "nxapi",
 …
 }
 
# ルールのパスを指定
 "naxsi" : {
 "rules_path" : "/usr/local/nginx/conf/naxsi_core.rules",
 "template_path" : [ "tpl/"],
 "geoipdb_path" : "nx_datas/country2coords.txt"
 },
 …
}
```

# Nginxの設定

80番ポートで接続を受け付け、安全な接続を8080番へとProxyしています。
閾値以上の接続は、リターンコード[481]を返します。

##　Sample(学習モード)
```nginx:/usr/local/nginx/conf/nginx.conf
http {
     # Naxsiのディフォルトルールの読み込み
     include        /usr/local/nginx/conf/naxsi_core.rules;
     
     server {
          listen       80;
          server_name  hogehoge.com;
          
          access_log   /var/log/nginx/hogehoge.com_access80.log main;
          error_log    /var/log/nginx/hogehoge.com_error80.log debug;
          # エラー出力を”debug”にしないと、ルールの生成が行われないので注意
          # error_log    /var/log/nginx/hogehoge.com_error80.log warn;
          
          location / {
               proxy_pass http://127.0.0.1:8080/;
               proxy_set_header Host hogehoge.com;

               #学習モードを有効にする
               LearningMode;
						   # 自動学習ルールを一旦読み込ませない(現時点でファイルは存在しない)
               # include /usr/local/nginx/conf/my.rules;
               
               SecRulesEnabled;
               #SecRulesDisabled;
               DeniedUrl "/RequestDenied";
          
               # しきい値の設定
               ## check rules ##
               CheckRule "$SQL >= 8" BLOCK;
               CheckRule "$RFI >= 8" BLOCK;
               CheckRule "$TRAVERSAL >= 4" BLOCK;
               CheckRule "$EVADE >= 4" BLOCK;
               CheckRule "$XSS >= 8" BLOCK;
               ############
          }
          #リジェクトされた際のページ
          location /RequestDenied {
               return 481;
          }
     }
```
## Nginxの再起動
```bash:コマンド
# 設定ファイルの検証
/etc/init.d/nginx configtest
# 再起動
/etc/init.d/nginx restart
```

## 動作確認
サーバー内で動作検証を行います。
ラーニングモードなので、ブロックはされません。
```
curl "http://127.0.0.1/?a=<"
```
下記のようなログが出ていればNxasiは正常に動いています。
```bash:ログファイル
2016/06/23 22:18:47 [error] 13987#0: *1028 NAXSI_FMT: ip=127.0.0.1&server=127.0.0.1&uri=/&learning=1&vers=0.54&total_processed=358&total_blocked=27&block=1&cscore0=$XSS&score0=8&zone0=ARGS&id0=1302&var_name0=a, client: 127.0.0.1, server: , request: "GET /?a=< HTTP/1.1", host: "127.0.0.1"
```

# ホワイトリストの生成

想定される挙動をブラウザで行いログに貯めます。

ある程度ログがたまれば、ログよりホワイトリストの生成をします。

## ログファイルの読み込み
NginxのログをElasticSearchに読み込みます。
```bash:ルールの生成
./nxtool.py -c nxapi.json --files=/var/log/nginx/hogehoge.com_error.log
```

## ElasticSearch内のデータを確認します。
```
curl -XPOST "http://localhost:9200/nxapi/events/_search?pretty" -d '{}'
```

## 登録されたログの統計データを見ます（簡易）

```
./nxtool.py -c nxapi.json -x
```
```
# size :1000
# Whitelist(ing) ratio :
# false 100.0 % (total:750/750)
# Top servers :
# 123.123.123.123 97.87 % (total:734/750)
# 127.0.0.1 2.13 % (total:16/750)
# Top URI(s) :
# /index.php/ccm/system/dialogs/block/edit/submit 49.33 % (total:370/750)
# /index.php/ccm/system/dialogs/page/add_block/submit 22.0 % (total:165/750)
# / 20.93 % (total:157/750)
# /index.php/ccm/system/dialogs/file/upload_complete 3.73 % (total:28/750)
# /index.php/dashboard/system/seo/urls/save_urls 2.13 % (total:16/750)
# /index.php/ccm/system/file/upload 1.87 % (total:14/750)
# Top Zone(s) :
# BODY 64.0 % (total:480/750)
# ARGS 20.93 % (total:157/750)
# BODY|NAME 11.33 % (total:85/750)
# ARGS|NAME 3.73 % (total:28/750)
# Top Peer(s) :
# 121.121.121.121 76.53 % (total:574/750)
# 122.122.122.122 21.33 % (total:160/750)
# 127.0.0.1 2.13 % (total:16/750)
```

## ホワイトリストの生成
※実はここから手順がかなり怪しいです・・・
[ReadMe](https://github.com/nbs-system/naxsi/tree/master/nxapi
)には[Generate whitelists]項目があるのですが、ホワイトリストの設置について明記されてなく。
一応これで、リストが生成されているはずです。

```
./nxtool.py -c nxapi.json -f --slack --colors | grep BasicRule > /usr/local/nginx/conf/my.rules
```

##　本番設定
```/usr/local/nginx/conf/nginx.conf
http {
     
     server {

          #error_log    /var/log/nginx/hogehoge.com_error80.log debug;
          error_log    /var/log/nginx/hogehoge_error80.log warn;
          
          location / {
          
               #LearningMode; #Enables learning mode
               #自動学習モードをOFF
               include /usr/local/nginx/conf/my.rules;
               #自動学習したルールを反映
          }
     }
```
### Nginxの再起動
```bash:コマンド
#設定ファイルの検証
/etc/init.d/nginx configtest
#再起動
/etc/init.d/nginx restart
```

# その他
Nginxからのログの取り込みがプログラム経由なので、FluentとかLogstashとかに切り替えて、セミリアルタイムの取り込みに帰れると素敵だなと妄想してます。

若干ポエミーで尻すぼみな内容になってしまいました、ごめんなさい。