Fail2BanでSQLインジェクション対策(WAF)

Linux

インターネット上に公開するサーバーは、従来のファイアウォールや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インジェクション対策に利用することで自動化されたブロック、監視と通知機能をオープンソースで無料利用することができます。

簡単に設定できるので使わない理由はありません。