nginxでWAF(Web Application Firewall) を作る(第三回)
こんにちは。SIOS OSSエバンジェリスト/セキュリティ担当の面です。
数回に分けて、nginxでWAFをつくる方法を紹介しています。
前回、nginxとmod_securityのパッケージを作成しました。今回は、前回の作業で作成されたnginxとmodsecurityをインストールし、設定をしてい>きます。
nginxのバージョンアップについて
前回の記事公開の後、nginxもバージョンが上がっており、現在(2016/04/19)は1.9.14が最新となっています。
各バージョンアップの内容に関しては、下記のリンクに細かい記載があります。
今回の記事では最新のものを使用しますので、前回の記事でのnginx-1.9.12を1.9.14に更新します。
nginxのソースパッケージは、nginxのサイト: http://nginx.org/packages/mainline/rhel/7/SRPMS/から取得します。
今回は、nginx-1.9.14-1.src.rpmをダウンロードします。
- “rpm -Uvh nginx-1.9.14-1.src.rpm”として、nginx-1.9.14-1のSOURCE/SPECファイルを展開します。
- SPECファイルの、前回の記事と同じ箇所(“3. nginxのリビルド”を参照)を修正します。
--with-ipv6 \ --add-module=/home/sios/rpmbuild/BUILD/modsecurity-2.9.1/nginx/modsecurity \ %{?with_http2:--with-http_v2_module}")
- 今回のnginxのバージョンでは、リビルドに”perl-devel”, “perl-ExtUtils-Embed”が必要になるので、これらをインストールします。
[root@localhost ~]# yum -y install perl-devel perl-ExtUtils-Embed --snip-- 依存性関連をインストールしました: gdbm-devel.x86_64 0:1.10-8.el7 perl-ExtUtils-Install.noarch 0:1.58-286.el7 perl-ExtUtils-MakeMaker.noarch 0:6.68-3.el7 perl-ExtUtils-Manifest.noarch 0:1.61-244.el7 perl-ExtUtils-ParseXS.noarch 1:3.18-2.el7 systemtap-sdt-devel.x86_64 0:2.8-10.el7 完了しました!
- 前回と同様に、”rpmbuild”コマンドでnginxパッケージをリビルドします。
[sios@localhost SPECS]$ rpmbuild -ba --target=x86_64 ./nginx.spec ビルド対象プラットフォーム: x86_64 ターゲット x86_64 用にビルド中 --snip-- 実行中(%clean): /bin/sh -e /var/tmp/rpm-tmp.YUbb9Z + umask 022 + cd /home/sios/rpmbuild/BUILD + cd nginx-1.9.14 + /usr/bin/rm -rf /home/sios/rpmbuild/BUILDROOT/nginx-1.9.14-1.el7.centos.ngx.x86_64 + exit 0
- RPMS/x86_64以下にnginx-1.9.14-1のパッケージが作成されます。
[sios@localhost x86_64]$ pwd /home/sios/rpmbuild/RPMS/x86_64 [sios@localhost x86_64]$ ls nginx* nginx-1.9.14-1.el7.centos.ngx.x86_64.rpm nginx-debuginfo-1.9.14-1.el7.centos.ngx.x86_64.rpm nginx-module-geoip-1.9.14-1.el7.centos.ngx.x86_64.rpm nginx-module-image-filter-1.9.14-1.el7.centos.ngx.x86_64.rpm nginx-module-njs-0.0.20160329.91543c86f412-2.el7.centos.ngx.x86_64.rpm nginx-module-perl-1.9.14-1.el7.centos.ngx.x86_64.rpm nginx-module-xslt-1.9.14-1.el7.centos.ngx.x86_64.rpm
ネットワーク構成
今回作るnginx+WAFですが、既存のWebサーバになるべく手を掛けずに保護するという形にしたいため、下のようなネットワーク構成で作成します。
外部(アクセステストを行う)ホスト、ngin+WAFのホスト、ターゲットのホストはそれぞれ
- ext.localdomain
- nginx.localdomain
- target.localdomain
となっています。これらは、/etc/hostsファイルに直接書き込んで、全てのホスト間で名前解決ができるようにしてあります。
Virtualboxを使って検証環境を作成しているためにこのようなネットワークになっていますが、実運用環境では負荷分散のための複数NICなど、別途環境に合わせて下さい。
今回の検証環境では、nginx+WAFにPort80で接続すると、適切にフィルタリングを行い、tomcatがPort8080で動作しているマシンにフォワードします。
構築
1. nginx/mod_securityパッケージのインストール
インストール自体は単純に”rpm -ivh 「nginxのパッケージ」「mod_securityのパッケージ」”で完了します。
バージョンアップ等でバージョンを更新したい際には”rpm -Uvh”オプションで実施すれば、パッケージを新しい物に更新してくれます。
以下は、nginxのパッケージを-Uvhオプションで更新した際の例です。
[root@cent7mini sios]# rpm -Uvh ./nginx-1.9.14-1.el7.centos.ngx.x86_64.rpm 準備しています... ################################# [100%] 更新中 / インストール中... 1:nginx-1:1.9.14-1.el7.centos.ngx ################################# [ 50%] 整理中 / 削除中... 2:nginx-1:1.9.12-1.el7.centos.ngx ################################# [100%] [root@cent7mini sios]# rpm -qa|grep nginx
インストール後、確認のため、”systemctl start nginx”でnginxを起動します。外部ホスト(ext.localdomain)からhttp://nginx.localdomainにアクセスすると、下記のような画面が表示されます。
2. nginxの設定
- まず、nginx(192.168.56.102)にPort80で接続すると、tomcat(192.168.56.101、Port8080)に転送を行うようにnginxを設定します。/etc/nginx/conf.d/default.confを修正します。
server { listen 80; server_name nginx.localdomain; #charset koi8-r; #access_log /var/log/nginx/log/host.access.log main; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_max_temp_file_size 0; location / { proxy_pass http://target.localdomain:8080; root /usr/share/nginx/html; index index.html index.htm; }
listen、及びserver_nameは、nginx/WAFのListenポート番号とIPアドレス(又はFQDN)を指定します。
proxy_set_header句では、X-Forwarded-Forなどのヘッダをセットしています。
location / 以下の”proxy_pass”句で、リクエストの転送先とポート番号を設定します。
- インストール後、確認のため、”systemctl start nginx”でnginxを起動します。外部ホスト(ext.localdomain)からhttp://nginx.localdomainにアクセスすると、下記のように、192.168.56.101:8080に転送され、画面(サンプルではtomcat)が表示されます。
3. ModSecurityの設定
- /etc/nginx/mod_security.confを下記のように修正します。
- “SecRuleEngine DetectionOnly”を”SecRuleEngine On”に変更します。
- “SecUnicodeMapFile unicode.mapping 20127″を”#SecUnicodeMapFile unicode.mapping 20127″と、コメントにして読まないようにします。
- 設定ファイルの最後に、他の設定ファイル(ルールファイル)を読み込むように、行を付け加えます
# Load all Rule Include modsecurity.d/*.conf Include modsecurity.d/activated_rules/*.conf Include modsecurity.d/local_rules/*.conf
- 次に、/etc/nginx/conf.d/default.confを下記のように修正します。
location / { #Enable ModSecurity
- 設定ファイルの修正が終わったら、”systemctl restart nginx”で、nginxを再起動します。
4. ModSecurityのテスト
- 外部ホスト(ext.localdomain)からhttp://nginx.localdomainにアクセスすると、通常のtarget.localdomainの画面と同じものが表示されますが、http://nginx.localdomain/?union+selectにアクセスすると”403 Forbidden”が表示されます。
- この時、/var/log/modsec_audit.logには、下記のようなメッセージが表示されています。
Message: Access denied with code 403 (phase 2). Pattern match "(?i:\\b(?:(?:s(?:t(?:d(?:dev(_pop|_samp)?)?|r(?:_to_date|cmp))|u(?:b(?:str(?:ing(_index)?)?|(?:dat|tim)e)|m)|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha(1|2)?|oundex|chema|ig?n|pace|qrt)|i(?:s(null|_(free_lock|ipv4_compat|ipv4_mapped|ipv4| ..." at ARGS_NAMES:union select. [file "/etc/nginx/modsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line "125"] [id "950001"] [rev "2"] [msg "SQL Injection Attack"] [data "Matched Data: union select found within ARGS_NAMES:union select: union select"] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.9"] [maturity "9"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag "WASCTC/WASC-19"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/6.5.2"] Action: Intercepted (phase 2) Apache-Handler: IIS Stopwatch: 1460821546000764 764120 (- - -) Stopwatch2: 1460821546000764 764120; combined=402, p1=98, p2=269, p3=0, p4=0, p5=35, sr=8, sw=0, l=0, gc=0 Producer: ModSecurity for nginx (STABLE)/2.9.1 (http://www.modsecurity.org/); OWASP_CRS/2.2.9. Server: ModSecurity Standalone Engine-Mode: "ENABLED"
まとめ
今回はnginxとmodsecurityのパッケージのインストール方法と、WAFの簡単な組み立てまでを説明しました。
次回は更に細かくmodsecurityのルールについて、更に細かくみていきます。
—–