fail2banでWordPressのログイン攻撃を防ぐ
jetpackだとインストールしただけで簡単に防いでくれそうな感じでもあるのですが、jetpackの統計機能が無償では無くなったことと、jetpackは重い印象があるので、すでに使用しているfail2banでできないかと調査。1つのサーバで複数のWordPressサイトを運用している場合もWebサーバのログファイルは1つなのでまとめて対応できますしね。
Webで検索するとfilterがいくつか見つかったのですが、
failregex = ^<HOST> -.*"POST /wp-login.php HTTP.*$
だと
fail2ban-regex /var/log/httpd/access_log /etc/fail2ban/filter.d/apache-wplogin.conf --print-all-matched Running tests ============= Use failregex filter file : apache-wplogin, basedir: /etc/fail2ban Use log file : /var/log/httpd/access_log Use encoding : UTF-8 Results ======= Failregex: 2 total |- #) [# of hits] regular expression | 1) [2] ^<HOST> -.*"POST /wp-login.php HTTP.*$ `- Ignoreregex: 0 total Date template hits: |- [# of hits] date format | [87470] Day(?P<_sep>[-/])MON(?P=_sep)ExYear[ :]?24hour:Minute:Second(?:\.Microseconds)?(?: Zone offset)? `- Lines: 87470 lines, 0 ignored, 2 matched, 87468 missed [processed in 29.06 sec] |- Matched line(s): | xxx.xxx.xxx.xxx - - [14/Jul/2024:04:37:43 +0900] "POST /wp-login.php HTTP/1.1" 200 11936 "-" "Mozilla/5.0" | xxx.xxx.xxx.xxx - - [14/Jul/2024:05:01:02 +0900] "POST /wp-login.php HTTP/1.1" 200 11936 "-" "Mozilla/5.0" Missed line(s): too many to print. Use --print-all-missed to print all 87468 lines
で2件しかヒットせず、実際に動かしてみても一向に検知されていく気配がありません。
failregex = ^<HOST>.* "POST .*/wp-login.php([/\?#\\].*)? HTTP/.*" 200
だと
Results ======= Failregex: 51 total |- #) [# of hits] regular expression | 1) [51] ^<HOST>.* "POST .*/wp-login.php([/\?#\\].*)? HTTP/.*" 200 `- Ignoreregex: 0 total Date template hits: |- [# of hits] date format | [87529] Day(?P<_sep>[-/])MON(?P=_sep)ExYear[ :]?24hour:Minute:Second(?:\.Microseconds)?(?: Zone offset)? `- Lines: 87529 lines, 0 ignored, 51 matched, 87478 missed [processed in 30.26 sec] |- Matched line(s): | xxx.xxx.xxx.xxx - - [14/Jul/2024:04:37:43 +0900] "POST /wp-login.php HTTP/1.1" 200 11936 "-" "Mozilla/5.0" | xxx.xxx.xxx.xxx - - [14/Jul/2024:05:01:02 +0900] "POST /wp-login.php HTTP/1.1" 200 11936 "-" "Mozilla/5.0" | xxx.xxx.xxx.xxx - - [14/Jul/2024:20:23:32 +0900] "POST /wp-login.php?jetpack-protect-recovery=true HTTP/1.1" 200 11929 "https://xxx.xxx/wp-login.php" "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" | xxx.xxx.xxx.xxx - - [15/Jul/2024:04:06:22 +0900] "POST //wp-login.php?jetpack-protect-recovery=true HTTP/1.1" 200 11930 "https://xxx.xxx//wp-login.php" "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" | xxx.xxx.xxx.xxx - - [16/Jul/2024:22:32:48 +0900] "POST //wp-login.php HTTP/1.1" 200 11936 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" | xxx.xxx.xxx.xxx - - [16/Jul/2024:22:40:53 +0900] "POST //wp-login.php HTTP/1.1" 200 11937 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
な感じで元のもの以外も多くヒットしたので後者を採用することにします。
という訳で
/etc/fail2ban/jail.d/apache-wplogin.local [wplogin-iptables] enabled = true filter = apache-wplogin action = iptables-multiport[name="403", port="http,https", protocol="tcp"] logpath = /var/log/httpd/*access_log ignoreip = 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 maxretry = 5 findtime = 60 bantime = 1800
/etc/fail2ban/filter.d/apache-wplogin.conf [Definition] failregex = ^<HOST>.* "POST .*/wp-login.php([/\?#\\].*)? HTTP/.*" 200 ignoreregex =
で始めて見て様子見。
fail2ban-client status wplogin-iptables Status for the jail: wplogin-iptables |- Filter | |- Currently failed: 0 | |- Total failed: 14 | `- File list: /var/log/httpd/access_log /var/log/httpd/ssl_access_log `- Actions |- Currently banned: 0 |- Total banned: 0 `- Banned IP list:
という感じで検知はしている模様。