Contents
Overview
Apache で ModSecurity (WAF) を有効化します。
WAF は Web セキュリティに非常に有用であり、アプリケーションの脆弱性を対策する際の強いソリューションの一つです。もちろん、アプリケーションセキュリティは WAF だけではなく、アプリケーション自体のセキュリティ対策、ミドルウェアレベルでのセキュリティ対策も非常に重要です。一方、WAF は複雑な仕組みであるため、エンタープライズレベルの導入のハードルは高い方だと言えます。WAF 自体が複雑であることもありますが、もう一つの大きな問題が技術組織の縦割りです。
筆者のコア技術はネットワーク・サーバーですが、とあるきっかけで WAF を担当していた時期が数年ありました。その時に、WAF を通じて学んだことは以下の通りです。
- WAF の導入は、それまで以上にディープな部署間の連携が必要となる。
- WAF の導入はアーキテクチャ的にミドルウェア上、またはロードバランサー上に実装されるため、組織的に見るとインフラ担当の範疇になる。
- とはいえ、アプリの細かい挙動に密接になるため、アプリ担当も WAF を理解し、どのような影響があるかを把握する必要がある。また、WAF 導入後のアプリの正常性はアプリ担当が判断せざるを得ないため、アプリとしてのテストが最も重要である。
- 上記を踏まえた上で、PM としては、アプリもインフラもハンドリングしなければならないため、それぞれで一定の独立性を保ててきた組織風土では連携が難しい。
- 上記を整理して WAF を導入できたとして、WAFの性質上、セキュリティ運用は重要であり、SoC などが存在しない場合は、運用面の建て付けも困難である。
つまり、WAF には組織体制も重要であり、本来はネットワーク、サーバー、アプリ、セキュリティの各エンジニアが必要となります。上記のようなハードルをクリアできなそうなら、WAF の引き合いは最悪の場合、断るという選択肢も考慮する必要があるでしょう。
前提条件
- こちらを参考に Apache をインストール済みであること。
インストール
modsecurity-crs (Core Rule Set) は libapache2-mod-security2 の依存関係により合わせてインストールされます。
myadmin@ubuntu:~$ sudo apt -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold install libapache2-mod-security2
/etc/modsecurity/modsecurity.conf-recommended
推奨設定として modsecurity.conf-recommended が用意されています。基本的にはこれをベースにして、modsecurity.conf を作成します。デフォルト値は下記の通りです。
myadmin@ubuntu:~$ grep -v -e '^\s*#' -e '^\s*$' /etc/modsecurity/modsecurity.conf-recommended | expand | tr -s [:space:] | sed 's/^\s/ /g'
SecRuleEngine DetectionOnly
SecRequestBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "application/json" \
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyInMemoryLimit 131072
SecRequestBodyLimitAction Reject
SecRule REQBODY_ERROR "!@eq 0" \
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
"id:'200003',phase:2,t:none,log,deny,status:400, \
msg:'Multipart request body failed strict validation: \
PE %{REQBODY_PROCESSOR_ERROR}, \
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
DB %{MULTIPART_DATA_BEFORE}, \
DA %{MULTIPART_DATA_AFTER}, \
HF %{MULTIPART_HEADER_FOLDING}, \
LF %{MULTIPART_LF_LINE}, \
SM %{MULTIPART_MISSING_SEMICOLON}, \
IQ %{MULTIPART_INVALID_QUOTING}, \
IP %{MULTIPART_INVALID_PART}, \
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
SecPcreMatchLimit 100000
SecPcreMatchLimitRecursion 100000
SecRule TX:/^MSC_/ "!@streq 0" \
"id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
SecTmpDir /tmp/
SecDataDir /tmp/
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABDEFHIJZ
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecUnicodeMapFile unicode.mapping 20127
SecStatusEngine On
/etc/modsecurity/modsecurity.conf
modsecurity.conf を作成します。SecRuleEngine DetectionOnly を On に変更しています。DetectionOnly は検出(ログの記録)だけ行いブロックはしません。SecResponseBodyAccess は Off に変更しています。CentOS ではデフォルトが Off だっと思いますが Ubuntu では On です。これはその名の通りレスポンスデータもWAF の監査対象とするものですが、例えば SQL 文を説明した記事があるとブロックされる可能性があります。実際の WAF の運用においてもレスポンスデータを監査対象とすることはほとんどのケースでないでしょう。
myadmin@ubuntu:~$ sudo tee /etc/modsecurity/modsecurity.conf <<"EOF"
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "application/json" \
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyInMemoryLimit 131072
SecRequestBodyLimitAction Reject
SecRule REQBODY_ERROR "!@eq 0" \
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
"id:'200003',phase:2,t:none,log,deny,status:400, \
msg:'Multipart request body failed strict validation: \
PE %{REQBODY_PROCESSOR_ERROR}, \
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
DB %{MULTIPART_DATA_BEFORE}, \
DA %{MULTIPART_DATA_AFTER}, \
HF %{MULTIPART_HEADER_FOLDING}, \
LF %{MULTIPART_LF_LINE}, \
SM %{MULTIPART_MISSING_SEMICOLON}, \
IQ %{MULTIPART_INVALID_QUOTING}, \
IP %{MULTIPART_INVALID_PART}, \
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
SecPcreMatchLimit 100000
SecPcreMatchLimitRecursion 100000
SecRule TX:/^MSC_/ "!@streq 0" \
"id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
SecResponseBodyAccess Off
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
SecTmpDir /tmp/
SecDataDir /tmp/
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABDEFHIJZ
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecUnicodeMapFile unicode.mapping 20127
SecStatusEngine On
EOF
設定の有効化
下記のコマンドにより mods-available/security2.conf, security2.load のシンボリックリンクが mods-enabled に作成されますが、Ubuntu では libapache2-mod-security2 のインストール時点で有効になっているため、この操作は不要です。
myadmin@ubuntu:~$ sudo a2enmod security2
設定を有効化します。
myadmin@ubuntu:~$ sudo systemctl restart apache2.service && systemctl status apache2.service
正常性確認
phpinfo の内容がちょうど WAF のルールに一致してブロックされますので、PHP と同じように確認します。下記の PHP スクリプトを作成します。ブラウザから Web サーバーにアクセス ( http://[ fqdn ]/info.php ) してブロックされることを確認します。ブラウザでは Forbidden You don't have permission to access this resource.
と出力されます。ログは /var/log/apache2/error.log
, /var/log/apache2/modsec_audit.log
で確認します。
myadmin@ubuntu:~$ echo '<?php phpinfo(); ?>' | sudo tee /var/www/html/info.php
PHP スクリプトを削除します。
myadmin@ubuntu:~$ sudo rm -f /var/www/html/info.php
ホワイトリスト
WAF を有効化した際、かなりのケースで誤検知が発生します。誤検知というと WAF のバグのように聞こえますが、WAF 観点ではアプリケーションの仕様に問題があるとも言えます。もちろん、WAF のシグネチャに問題がある場合もあるでしょう。WAF の仕組み上、このような状況はどうしても発生しますので、原則として、WAF を有効化した上で、アプリケーションの正常性確認を行い、必要に応じてホワイトリストでのチューニングが必要となります。一方で、ホワイトリストをシグネチャベースで設定する場合、その id の防御機能が無効化されることになりますので、以降はアプリケーション側の責任が増加します。場合によってはアプリケーションの仕様変更を行う場合もあります。また、WAF とアプリケーションの責任者が分かれている場合、アプリケーションの正常性を判定できるのはアプリケーションの責任者である点を理解する必要があります。
/var/log/apache2/modsec_audit.log
WAF の検知ログは /var/log/apache2/modsec_audit.log に出力されます。ここではログの出力例を省略しますが、一般的なログに比べかなり見づらいと思います。大抵は A, B, F, H, Z などのセクションに分かれてログが出力されており、どのシグネチャで検知したかは H セクションに出力されています。
設定ファイルの配置
Ubuntu で ModSecurity をインストールすると以下のファイルが生成されます。この内容の通り、/etc/modsecurity/*.conf を読み込む設定となっているため、追加の設定は別ファイルにまとめると良いと思います。
myadmin@ubuntu:~$ cat /etc/apache2/mods-enabled/security2.conf
<IfModule security2_module>
# Default Debian dir for modsecurity's persistent data
SecDataDir /var/cache/modsecurity
# Include all the *.conf files in /etc/modsecurity.
# Keeping your local configuration in that directory
# will allow for an easy upgrade of THIS file and
# make your life easier
IncludeOptional /etc/modsecurity/*.conf
# Include OWASP ModSecurity CRS rules if installed
IncludeOptional /usr/share/modsecurity-crs/*.load
</IfModule>
/etc/modsecurity/whitelist.conf
本稿では、ホワイトリストの設定を /etc/modsecurity/whitelist.conf にまとめる設計とします。modsec_audit.log の内容を参考に以下のように設定することで、特定の id を除外することができます。以下はシンプルな例となりますが、LocationMatch 等を使用して特定のディレクトリやファイル単位で制御することも可能です。
myadmin@ubuntu:~$ sudo tee /etc/modsecurity/whitelist.conf <<"EOF"
SecRuleRemoveById 920350
SecRuleRemoveById 949110
EOF