インターネット上に公開するサーバーは、従来のファイアウォールやIDS/IPSでは防ぐことができない攻撃に対しても対策するのが当たり前になってきました。
WAFなどを利用するとコストが掛かるので、費用がかからないように簡易WAFとしてFail2Banを利用することにしました。

- Fail2Banを利用したWAFを構築したい
- 無料でWAFとして代用したい
- 動的ファイアウォールを構築したい
Fail2Banを簡易WAF・不正侵入防止システムとして動作するまでを解説します。
私は Rocky Linux を利用しています。「Rocky Linux (ロッキーリナックス)」と「AlmaLinux(アルマリナックス)」という Linux ディストリビューションは CentOS Linux の後継として RHEL(Red Hat Enterprise Linux)の完全クローンです。
Fail2Banって
Fail2Banとは
Fail2Banとはログを監視し、不審なアクセスを検出すると通信を遮断(BAN)します。指定時間が経過したらブロックを自動的に解除(UNBAN)を実行してくれる便利なツールです。
詳しく説明した記事がありますので、こちらも確認することをお勧めします。
関連記事 Rocky LinuxとAlmaLinuxに Fail2ban をインストール 完全ガイド
SQLインジェクション対策のFail2Ban構成
今回は Fail2Ban をSQLインジェクション対策を目的に簡易WAFとして構築します。
SQLインジェクション対策は、プログラムコードの中にエスケープ処理、サニタイジングを組み込むのは当然なのですが、どうしても「抜け」が発生したり、動作しなかったりすることが出てします。
不正対策は多段で防御することで安全性を向上させます。SQLインジェクションを試みるトラフィックは、通信自体をDropしてしまいます。トラフィックが流れてこないことは最強の不正対策です。
Firewalldの設定
Fail2Ban自体は通信遮断を行わず、実際に遮断を行うのはiptablesやfirewalldです。Rocky Linux は firewalld がインストールされているのでサービスを起動させます。合わせてOSが起動した時に自動起動するように設定を行います。
# systemctl start firewalld # systemctl enable firewalld
firewalld のデフォルト設定ではSSHしか通信許可されていません。
HTTPとHTTPS通信で fail2ban が動作するようにする場合は、firewalldに通信許可の設定を行います。
# firewall-cmd --add-service=http --zone=public --permanent # firewall-cmd --add-service=https --zone=public --permanent
これで firewalld の設定は完了です。
firewalld の動作状況を確認します。
# firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: ens160
sources:
services: dhcpv6-client http https ssh
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
HTTPとHTTPSを通信許可する設定が反映しています。
SQLインジェクションのフィルター作成
/etc/fail2ban/filter.d/ に各フィルタの設定ファイルがあります。検出する条件などを記載します。
SQLインジェクション用のフィルターはデフォルトでは提供されていませんので有志が作成してくれたフィルタを利用することにします。
https://github.com/TrogloGeek/fail2ban-apache-sqlinject/blob/master/apache-sqlinject.conf
ライセンス:(GNU General Public License v3.0)
このフィルターはApacheのログにSQLインジェクションに利用されるような文字列を検出してくれます。
# vi /etc/fail2ban/filter.d/apache-sqlinject.conf
# Fail2Ban configuration file # # Author: TrogloGeek (Damien VERON) # # $Revision: 1 $ # [Definition] sqlfragments_generic = union.*select|UNION.*SELECT|select.*from|delete.*from|update.*set|insert.*into|replace.*(value|set) sqlfragments_havij = and(\+|%%20)ascii%%28substring|and(\+|%%20)Length|union(\+|%%20)all(\+|%%20)select|and(\+|%%20)1%%3C1|and(\+|%%20)1%%3D1|and(\+|%%20)1%%3E1|and(\+|%%20)%%27.%%27%%3D%%27|%%2F\*%%21[0-9]+((\+|%%20)[0-9]*)?\*%%2F # Option: failregex # Notes.: Regex to try to detect SQL injection trials # Values: TEXT # #failregex = ^ -[^"]*"[A-Z]+\s+/[^"]*\?[^"]*(?:%(sqlfragments_generic)s|%(sqlfragments_havij)s)[^"]*HTTP[^"]*" #failregex = ^ - \w+ \[\] "(%(sqlfragments_generic)s|%(sqlfragments_havij)s)[^"]*HTTP[^"]*" #failregex = ^ -.*"(GET|POST|HEAD).*HTTP.*" failregex = ^ -.*(%(sqlfragments_generic)s|%(sqlfragments_havij)s)[^"]*HTTP[^"]* # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex =
SQLインジェクションのJAIL設定
fail2ban がSQLインジェクションと検出したときの設定を /etc/fail2ban/jail.d/ に設定します。
# vi /etc/fail2ban/jail.d/apache-sqlinject.conf
[apache-sqlinject] # 有効化 enabled = true # 作成したフィルターを指定 filter = apache-sqlinject # firewalldで遮断するプロトコル port = http,https # 検索するログファイル logpath = /var/log/httpd/access.log # 遮断時間 bantime = 10m # リトライ回数 maxretry = 1
SQLインジェクション fail2ban への読み込み
SQLインジェクションの設定を追加したら設定を反映させます。
# systemctl restart fail2ban
フィルターを正しく読み込むとログに出力されます。
/var/log/fail2ban.log
fail2ban.server : INFO Starting Fail2ban v0.11.2
fail2ban.observer: INFO Observer start...
fail2ban.database: INFO Connected to fail2ban persistent database '/var/lib/fail2ban/fail2ban.sqlite3'
fail2ban.jail : INFO Creating new jail 'apache-sqlinject' ← apache-sqlinjectの設定が有効化
fail2ban.jail : INFO Jail 'apache-sqlinject' uses poller {}
fail2ban.jail : INFO Initiated 'polling' backend
fail2ban.filter : INFO maxRetry: 1
fail2ban.filter : INFO encoding: UTF-8
fail2ban.filter : INFO findtime: 600
fail2ban.actions : INFO banTime: 600
fail2ban.filter : INFO Added logfile: '/var/log/httpd/access.log' (pos = 12604131, hash = 6b8ff3f40902e3fc618c6d56b32c5b0a)
fail2ban.jail : INFO Jail 'apache-sqlinject' started
動作テストとしてSQLインジェクションと認識するアクセスをブラウザから実施してください。正しく動作していれば通信が遮断されます。
ブラウザの場合はキャッシュなどの影響を受けるので、あれ?って思うことが発生するのでログやコマンドから動作チェックを実施してください。
SQLインジェクションのfail2ban動作チェック
fail2ban-regexコマンドによるフィルター動作テスト
フィルターが想定通りに動作するか、ログファイルと、作成したフィルターを利用して動作テストを行うことができます。
# fail2ban-regex [ログファイル] [フィルターファイル]
# fail2ban-regex /var/log/httpd/access.log /etc/fail2ban/filter.d/apache-sqlinject.conf Running tests ============= Use failregex filter file : apache-sqlinject, basedir: /etc/fail2ban Use log file : /var/log/httpd/access.log Use encoding : UTF-8 Results ======= Failregex: 5 total |- #) [# of hits] regular expression | 1) [5] ^ -.*(union.*select|UNION.*SELECT|select.*from|delete.*from|update.*set|insert.*into|replace.*(value|set)|and(\+|%20)ascii%28substring|and(\+|%20)Length|union(\+|%20)all(\+|%20)select|and(\+|%20)1%3C1|and(\+|%20)1%3D1|and(\+|%20)1%3E1|and(\+|%20)%27.%27%3D%27|%2F\*%21[0-9]+((\+|%20)[0-9]*)?\*%2F)[^"]*HTTP[^"]* `- Ignoreregex: 0 total Date template hits: |- [# of hits] date format | [108236] Day(?P<_sep>[-/])MON(?P=_sep)ExYear[ :]?24hour:Minute:Second(?:\.Microseconds)?(?: Zone offset)? `- Lines: 108236 lines, 0 ignored, 5 matched, 108231 missed ← 5件のログがマッチ [processed in 34.43 sec]
動作テストとしてSQLインジェクションと認識するアクセスをブラウザから実施してください。その時のApacheのログをfail2ban-regexコマンドに読み込ませて解析したところ、想定通りSQLインジェクションとして認識しました。
あとがき
fail2banは、サーバーのログファイルを監視し、不正なアクセスを自動的にブロックすることで、セキュリティを向上させるツールです。
fail2ban をSQLインジェクション対策に利用することで自動化されたブロック、監視と通知機能をオープンソースで無料利用することができます。
簡単に設定できるので使わない理由はありません。