ModSecurity(Web Application Firewall)の設定について(CentOS 7)



●概要

 ModSecurityはオープンソースで開発されている WAF(Web Application Firewall)で、無償で利用することができます。
 WAFとは、Web アプリケーションにリクエストが送信される手前でリクエストを取得して、内容を精査し、問題があればリクエストを拒否します。これにより仮にWebアプリケーションに脆弱性があったとしても WAF が守ってくれます。
 WAFにも偽陽性や偽陰性の問題があるので、過信することはよくないですが、改修不能な Web アプリケーションの保護や多層防御の一手法として有効です。
 また、WAFには、ネットワーク型とホスト型がありますが、ModSecurityはホスト型のWAFになります。

 参考にしたページ
 オープンソースの WAF である ModSecurity を CentOS にインストールする
 WAF(Web Application Firewall)でWebサイトを脆弱性から守る
 CentOS6.5にWeb Application Firewallのmod_securityを入れてみる  ModSecurityの有効前後のベンチマークの記載あり

 更に、WAFまたは検知ルールのアップデートによって、それまでは問題がなかった設定でも問題が発生する可能性があります。WAFに関するアプリケーションに関しては

   パッケージの自動アップデートを行っている場合、WAFは対象外にする
   テスト環境で試験してから手動アップデートを行う
   アップデートをきちんと監視して、問題が発生した場合でも直ぐに対応できるようにする

といった対応をとる必要がでてきます。

●構築環境

 今回の構築環境は下記のとおりです。

  CentOS 7.1(64bit)
  Apache 2.4.6
  mod_security-2.7.3-5.el7
  mod_security_crs-2.2.6-6.el7
 なお、CRS (Core Rule Set)とは、ModSecurityで使用するルール集になります。
 また、今回対応する脆弱性は影響の大きい以下の2つのみとします。

  クロスサイト・スクリプティング
  SQL インジェクション

 これは、多くのルールを多くすると偽陽性(正しいリクエストであっても、不正なものと判定される)の可能性が高まり、正常にWebアプリケーションが動作しなくなることを防ぐためです。

●インストール

 CentOS 7では通常どおりのインストール方法でインストールできますが、CentOS 6ではEPELリポジトリからでないとインストールできませんでした。
 EPELリポジトリの追加方法は、下記を参照してください。

  RPMforge EPEL Remiリポジトリインストール

 mod_security_crsを追加するのを忘れないでください。忘れるとModSecurityは動作しても何も防御しません。
# yum --enablerepo=epel install mod_security mod_security_crs
# service httpd restart
 これで、ModSecurityが有効になりました。以下のアドレスにアクセスし拒否されれば、問題なくModSecurityが動作しています。
http://hostname/index.php?union+select
 しかし、この場合のたくさんのルールが適用されているため、これをクロスサイト・スクリプティングとSQLインジェクションに限定します。
 下記コマンドで設定ファイルを編集します。
# vi /etc/httpd/conf.d/mod_security.conf
 以下の3行目をコメントアウトして、その下に2行追加します。これで、2種類のルールのみが適用されるようになります。
# ModSecurity Core Rules Set configuration
Include modsecurity.d/*.conf
#Include modsecurity.d/activated_rules/*.conf
Include modsecurity.d/activated_rules/modsecurity_crs_41_xss_attacks.conf
Include modsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf
 Webサーバを再起動します。
# service httpd restart
 これで動作確認の準備は完了です。

●偽陽性のテスト

 まず、ModSecurityを攻撃を検知のみにしてログを取るように設定し、Webアプリケーションに全体に対して一通りの操作をします。
 ModSecurityをログの取得のみにするには、以下のファイルを編集します。
# vi /etc/httpd/conf.d/mod_security.conf
 そして、SecRuleEngineをDetectionOnlyに変更して設定を保存します。
#SecRuleEngine On
SecRuleEngine DetectionOnly
 Webサーバを再起動します。
# service httpd restart
 通常の操作が偽陽性として検知されたログは、/var/log/httpd/modsec_audit.logに保存されます。ログの内容を確認して、例外処理をmod_security.confに記述していきます。

●Mod Securityログの確認

 Mod Securityのログファイルは、上記、mod_security.conf中で出力先が定義されています(SecAuditLog)。
 デフォルトは、/var/log/httpd/modsec_audit.logに出力されるよう設定されています。このログを確認する事で、どのようなアクセスがチェックに引っかかったかを判断する事ができます。
 下記に、出力ログの一例を示します。恐らく、かなり判りにくいと思います。
 Mod Securityに相当慣れていないと、このログを見てどのような問題が発生しているのか判定するのは難しいでしょう。

--d3ae0f4f-A--
[20/Apr/2014:22:44:16 +0900] U1PPMKwfEiEAAC59@iUAAAAH 122.18.213.123 48448 172.31.18.33 80
--d3ae0f4f-B--
GET / HTTP/1.0
User-Agent: check_http/v1.4.16 (nagios-plugins 1.4.16)
Connection: close

--d3ae0f4f-F--
HTTP/1.1 302 Found
Pragma: no-cache
Cache-Control: no-cache, no-store, must-revalidate, max-age=0
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Location: http://www.agilegroup.co.jp/index.html
Content-Type: text/html;charset=UTF-8
Content-Length: 0
Connection: close

--d3ae0f4f-E--

--d3ae0f4f-H--
Message: Warning. Operator EQ matched 0 at REQUEST_HEADERS. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_21_protocol_anomalies.conf"] [line "29"] [id "960008"] [rev "2"] [msg "Request Missing a Host Header"] [severity "WARNING"] [ver
"OWASP_CRS/2.2.6"] [maturity "9"] [accuracy "9"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_HOST"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"]
Message: Warning. Operator EQ matched 0 at REQUEST_HEADERS. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_21_protocol_anomalies.conf"] [line "47"] [id "960015"] [rev "1"] [msg "Request Missing an Accept Header"] [severity "NOTICE"] [ver "OWASP_CRS/2.2.6"] [maturity "9"] [accuracy "9"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT"] [tag "WASCTC/WASC-21"] [tag
"OWASP_TOP_10/A7"] [tag "PCI/6.5.10"]
Message: Warning. Operator GE matched 5 at TX:inbound_anomaly_score. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_60_correlation.conf"] [line "37"] [id "981204"] [msg "Inbound Anomaly Score Exceeded (Total Inbound Score: 5, SQLi=, XSS=):
Request Missing an Accept Header"]
Apache-Handler: proxy-server
Stopwatch: 1398001456285107 2997 (- - -)
Stopwatch2 1398001456285107 2997; combined=1031, p1=272, p2=595, p3=3, p4=62, p5=97, sr=99, sw=2, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.7.3 (http://www.modsecurity.org/); OWASP_CRS/2.2.6.
Server: Apache
Engine-Mode: "DETECTION_ONLY"

--d3ae0f4f-Z--


●偽陽性判定があった場合

 問題ないリクエストが偽陽性判定された場合には、auditログを確認しid([id "XXXXXX"])を確認します。例外として mod_security.conf に除外設定を行います。
# vi /etc/httpd/conf.d/mod_security.conf
 以下を追記

  # id= 960008 は偽陽性
  SecRuleRemoveById 960008

 ※管理画面等の特定パスのみ除外したい場合、以下のように設定する事で対応可能
 (特定のディレクトリに対し、SecRuleEngine Offを指定してmod_security自体を無効にするといった指定も可能)
<LocationMatch /path/to/application>
  SecRuleRemoveById 960008
</LocationMatch>
 設定変更後はapacheを再起動します。
# /etc/rc.d/init.d/httpd restart
 これで設定変更の反映が完了しました。

●mod_securityのホワイトリスト、ブラックリストの書き方

 こちらのページを参考にしました。
 ただし、情報が古かったためかApacheの再起動が失敗しました。
 そのため、Reference Manualを参考にしました。

●ベンチマーク

 mod_securityの適用前後でベンチマークを計測してみました。

  適用前
# ab -n 100 -c 10 http://www.bigbang.mydns.jp/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking www.bigbang.mydns.jp (be patient).....done
Server Software:        Apache/2.4.6
Server Hostname:        www.bigbang.mydns.jp
Server Port:            80
Document Path:          /
Document Length:        37126 bytes
Concurrency Level:      10
Time taken for tests:   2.356 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      3732500 bytes
HTML transferred:       3712600 bytes
Requests per second:    42.44 [#/sec] (mean)
Time per request:       235.634 [ms] (mean)
Time per request:       23.563 [ms] (mean, across all concurrent requests)
Transfer rate:          1546.90 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.8      1       6
Processing:   159  227  22.0    229     269
Waiting:       28  126  21.6    124     218
Total:        160  228  21.9    230     269
Percentage of the requests served within a certain time (ms)
  50%    230
  66%    238
  75%    245
  80%    248
  90%    256
  95%    260
  98%    267
  99%    269
 100%    269 (longest request)

  適用後
# ab -n 100 -c 10 http://www.bigbang.mydns.jp/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking www.bigbang.mydns.jp (be patient).....done
Server Software:        Apache/2.4.6
Server Hostname:        www.bigbang.mydns.jp
Server Port:            80
Document Path:          /
Document Length:        37126 bytes
Concurrency Level:      10
Time taken for tests:   2.731 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      3732500 bytes
HTML transferred:       3712600 bytes
Requests per second:    36.62 [#/sec] (mean)
Time per request:       273.107 [ms] (mean)
Time per request:       27.311 [ms] (mean, across all concurrent requests)
Transfer rate:          1334.65 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.6      1       4
Processing:    95  257  56.8    268     366
Waiting:       65  194  64.5    199     362
Total:         95  258  56.8    269     366
Percentage of the requests served within a certain time (ms)
  50%    269
  66%    286
  75%    300
  80%    304
  90%    322
  95%    345
  98%    362
  99%    366
 100%    366 (longest request)
 同じネットワーク内の別のマシンから実施してみましたが、0.4秒ほど反応が遅くなっています。

●ルールの書式

  セキュリティルールの記載方法は下記のようになっています。
SecRule VARIABLES OPERATOR [ACTIONS]
 パラメータの種類が非常に多いので、下記URLを参照してください。
https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual

●独自のルールを設定する

 未記載

●AuditoConsoleのインストールについて

 結論、うまく動作しなかった(2016年10月末現在)。
 環境:
  Fedora 24
  Apache Tomcat/8.0.36
  JVM Version/1.8.0_111-b16
  MySQL/Ver 15.1 Distrib 10.1.18-MariaDB,

 実施した作業内容は下記のとおりです。

---------- ここから ----------

下記URLを参照してAuditConsoleをインストールします。

 参考URL:3.2.2. CentOS/RedHat Installation

 起動しますが、JDKが見つからないと怒られました。

# systemctl status -l auditconsole
● auditconsole.service - LSB: AuditConsole Server basic start/shutdown script
Loaded: loaded (/etc/rc.d/init.d/auditconsole; bad; vendor preset: disabled)
Active: failed (Result: exit-code) since 金 2016-10-28 08:45:16 JST; 12s ago
Docs: man:systemd-sysv-generator(8)
Process: 9247 ExecStart=/etc/rc.d/init.d/auditconsole start (code=exited, status=1/FAILURE)

10月 28 08:45:16 server01 systemd[1]: Starting LSB: AuditConsole Server basic start
10月 28 08:45:16 server01 auditconsole[9247]: Error: no JDK found - please set JAVA
10月 28 08:45:16 server01 systemd[1]: auditconsole.service: Control process exited,
10月 28 08:45:16 server01 systemd[1]: Failed to start LSB: AuditConsole Server basi
10月 28 08:45:16 server01 systemd[1]: auditconsole.service: Unit entered failed sta
10月 28 08:45:16 server01 systemd[1]: auditconsole.service: Failed with result 'exi


 下記より最新のJDKをダウンロードしてインストールします。

 参考URL:Java SE Development Kit 8 Downloads
# rpm -Uvh /root/jdk-8u111-linux-i586.rpm 
準備しています...              ################################# [100%]
更新中 / インストール中...
   1:jdk1.8.0_111-2000:1.8.0_111-fcs  ################################# [100%]
Unpacking JAR files...
	tools.jar...
	plugin.jar...
	javaws.jar...
	deploy.jar...
	rt.jar...
	jsse.jar...
	charsets.jar...
	localedata.jar...
 再度起動しますが、まだ、JDKが見つからないと言っています。環境変数にJavaのパスを追加します。
# vi /etc/profile
(最終行に以下を追加)
##### JDK環境設定 #####
export JAVA_HOME=/usr/java/latest
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/tools.jar
 追加後、再起動しますが結果は同じでした。どうもこのJDKの設定ではないようです。インターネットで調べたところ下記の記事がありました。

 参考URL:[Console-users] Graphs not loading

 試してみます。
# ln -s /usr/lib/jvm/java-openjdk/ /usr/lib/jvm/java-6-openjdk
# ls -l /usr/lib/jvm/java-6-openjdk
lrwxrwxrwx 1 root root 26 10月 28 09:27 /usr/lib/jvm/java-6-openjdk -> /usr/lib/jvm/java-openjdk/
# systemctl start auditconsole
● auditconsole.service - LSB: AuditConsole Server basic start/shutdown script
   Loaded: loaded (/etc/rc.d/init.d/auditconsole; bad; vendor preset: disabled)
   Active: active (running) since 金 2016-10-28 09:28:11 JST; 9s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 26083 ExecStart=/etc/rc.d/init.d/auditconsole start (code=exited, status=0/SUCCESS)
    Tasks: 12 (limit: 512)
(以下、省略)
 うまく起動しました。次にデータベースを用意します。

 参考URL:3.2.6. Setting up an external Database

 Tomcatが動作しなくなってしまいました。さきほど作成したシンボリックリンクを削除します。
# rm usr/lib/jvm/java-6-openjdk
 状況は変わりません。Tomcatを再インストールしてみましたが状況は変わりませんでした。
 Auditconsoleを停止すると、Tomcatは正常起動するようですが8080ポートに接続できません。
 AuditconsoleをアンインストールしTomcatを再起動しましたが状況は変わりませんでした。(HTTP????? 404 - /WEB-INF/content/login.jsp)
 Tomcatをアンインストールし、サーバ再起動後、Tomcatを再インストールで正常にTomcatが動作しました。



 再度チャレンジします。
 AuditConsoleをインストールし、起動します。この状態ではTomcatは正常に動作します。
 AuditConsoleの最新版のWarファイルをダウンロードし、/usr/share/tomcat/webappsに保存しますがTomcatアプリケーションが起動しません。
 この状態でAuditConsoleを再起動すると8080番ポートに接続しても接続出来なくなります。
 AuditConsoleアプリケーションを削除し、AuditConsoleを再起動するとTomcatに正常に接続出来るようになります。

---------- ここまで ---------- 

●NextCloudで大きなファイルをアップロードできない

 Windows10上で利用しているNextCloudクライアントからサーバへ同期しようとすると同期に失敗しエラーが表示されます(同期対象ファイルサイズは1.9GB)。
 サーバ側で下記のようなログが記録されていました。

# less /var/log/httpd/modsec_audit.log

[Fri Jul 22 22:44:12.692726 2022] [:error] [pid 1212106:tid 140183034918656] [client 192.168.0.1:51180] [client 192.168.0.1] ModSecurity: Request body (Content-Length) is larger than the configured limit (536870912). [hostname "www.bigbang.mydns.bz"] [uri "/nextcloud/remote.php/dav/uploads/hogehoge/1003468202/0000000000000013"] [unique_id "YtqprB0f@-ZsMprN-MAgIAAAAEc"]


 このため、ModSecurity(Web Application Firewall)の設定を2箇所変更しました。
# vi /etc/httpd/conf.d/mod_security.conf

SecRequestBodyLimit 536870912
 ↓
SecRequestBodyLimit 2147483648

SecRequestBodyNoFilesLimit 536870912
 ↓
SecRequestBodyNoFilesLimit 2147483648

# systemctl restart httpd
 以上により、正常にアップロード出来るようになりました。