fail2banとFreeBSDのpfで通信がただちに遮断されない?

クラッキング
©いらすとや.

2020年9月末現在にfail2banに入っているpfパケットフィルタ用のアクション設定の内、Ban対象IPアドレスが発生した際に発動するactionbanは以下のようなの。条件によって多少違うかもだけど。

block drop quick proto tcp from <f2b-フィルタルール名> to any

仮にフィルタルール名をexampleとしてルールを作成して運用し、Ban対象になるログが記録されたとする。そのIPアドレスは192.168.0.11とする。

/var/log/fail2ban.log
2020-09-30 12:00:00,000 fail2ban.actions        [191]: NOTICE  [example] Ban 192.168.0.11
fail2banのフィルタルールexampleが作ったルール
# pfctl -a "f2b/example" -s rules
block drop quick proto tcp from  to any
f2b-exampleのフィルタルールでBanされているIPアドレスリスト
# pfctl -a "f2b/example" -t f2b-example -T show
   192.168.0.11
   192.168.0.47

fail2banでexampleフィルタルールを有効にしたことで発生しているルールは予定どおりで問題ないように見える。
BanされているIPアドレスリストに192.168.0.11が含まれているので予定どおりの動作になっている。
そして、暫く後に確認したところ、192.168.0.11からはもう訪れることがなくなっていることが確認できた。

ところが

もう一度fail2banのログを見る

/var/log/fail2ban.log
2020-09-30 12:00:10,500 fail2ban.filter         [191]: INFO    [localban] Found 192.168.0.11 - 2020-09-30 12:00:10
2020-09-30 12:00:11,000 fail2ban.actions        [191]: NOTICE  [localban] 192.168.0.11 already banned

しばらくこんなのが続いていた。「アクセスされたけど既にBanされてる」というメッセージ。凄い矛盾というかおかしな話。

サービスログを確認する
Sep 30 11:59:40 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 11:59:50 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:00:00 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:00:10 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:00:20 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:00:30 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:00:40 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:00:50 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:01:00 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:01:10 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:01:20 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:01:30 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:01:40 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:01:50 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:02:00 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:02:10 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:02:20 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:02:30 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:02:40 hoge example[25572]: client=[192.168.0.11], undesirable record
Sep 30 12:02:50 hoge example[25572]: client=[192.168.0.11], undesirable record

黄色の行がfail2banによってBanが確定したログ。Banされた時刻以降もたしかにアクセスが続いている。

12:00:00にBanされたら以降のアクセスは無いことを期待すると思うが、実際にはしばらく(意外と長く)アクセスが続くことがある。
fail2banがログを読んでBanと認識したのが実際には12:00:00より数分遅いのかというとそうではないらしい。そしてBan対象の192.168.0.11から全く新しい通信を行おうとした場合は12:00:00直後からでもアクセスできないっぽい。
どうも、セッションが切断されずに継続される場合はBanを発生させても通信は遮断されないよう。辞めた従業員を翌日以降も顔パスで会社に出入りさせてる警備員みたいな感じ。
この挙動はfail2banではなくpfが引き起こしてるみたい。

ググってみたらこんなやりとりがあった。

https://github.com/fail2ban/fail2ban/issues/1924

攻撃的?なぜ揉めてるのかニュアンスが理解できないのだが、単純にBanしたついでに pfctl -k IPアドレス を実行するんで良くない?ってことでこれを採用。

pf用のアクションを決めているファイルは/usr/local/etc/fail2ban/action.d/pf.conf

actionban = <pfctl> -t <tablename>-<name> -T add <ip> && <pfctl> -k <ip>

黄色の部分が元のアクションから増えた部分。
いまのところ、これで期待したとおりBan後は問答無用で遮断されるという動作になっている。

つまり、長らくpfの動きを正しく理解せずに使ってたということだけど、dropルールより状態を優先させる動きがデフォルトってヘンじゃないかしら?

タイトルにはFreeBSDって付けてるが、FreeBSD以外でもpfが使えるOSでおそらく同じ?

「使用していない JavaScript の削除」と「使用していない CSS を削除してください」

最近はGoogleさんのウェブサイトのページの評価がうるさくなってユーザーエクスペリエンスというものが重視される傾向。今年はCore Web Vitals(コアウェブバイタル)とかいうものに振り回された(振り回されている?)ウェブサイトの管理者も多い筈。 コアウェブバイタルの3つLCP, FID, CLS、それとFCPの合わせて4つの指標が重要ね。コアウェブバイタルは今年は猶予期間だからとのんびり構えないで早めに対処した方が良さげ。対処するとページの表示速度が改善され、より多くの閲覧者が訪れる、少なくとも減りはしないことが期待される。
難しそうだからと途方に暮れることはなく、GoogleのPageSpeed InsightsやChromeブラウザ内蔵デベロッパーツールのLighthouseを使えばご丁寧に改善点を教えてくれるので1つ1つ潰していくだけ。
で、今回は難しそうで簡単そうでそうでもない「使用していない JavaScript の削除(Remove unused JavaScript)」と「使用していない CSS を削除してください(Remove unused CSS)」の2つの対処。

現在の「がとらぼ」は大きく2つに分かれていて「画面が暗いブログ」と「画面の明るい中華スマホのスペック紹介」になっている。1つのWordPressでテンプレートを2つ用意してブログとスマホ紹介で見た目が全く異なるようになっている。ブログ用の方はフルスクラッチの自作テンプレートでCSSも全部自作。スマホ用の方はテンプレート自体は自作だけど見た目の部分についてはほぼSemantic UIというフレームワークに頼っている。Semantic UIは導入そのものはとても簡単にできるのだが、単に「入れました、使いました」だとGoogleさんの評価が大変悪い。指摘されるのが「使用していないJS/CSSを削除してください」。今回はそれを改善する。
Semantic UI以外でも大きめのフレームワークを使うと同じ指摘を食らう筈だが、対処方法は同じなので少しは参考になる部分がある筈。

使用していないCSSを削除してください 1
PageSpeed InsightsでSemantic UIを使っているページを診断してみた。「改善できる項目」の中に「使用していない JavaScript の削除」と「使用していない CSS を削除してください」がある。(画像の赤い四角の部分)

使用していないCSSを削除してください 2
「使用していない JavaScript の削除」と「使用していない CSS を削除してください」をクリックするとそれぞれ指摘対象のJavascript, CSSファイルのPathが表示される。

この、「使用していない JavaScript の削除」と「使用していない CSS を削除してください」は指摘されているJS/CSSファイルが要らないから削除しろということではなく、指摘されているファイル内に使っていないコードが多すぎるのでそれを省けというもの。ここで指摘の意味を取り違えると対処方法がわからなくなる。Googleさんの指摘って意味が判らないのが多いから困る。

使用していないCSSを削除してください 3
Chromeブラウザを起動して[F12]キーを押す。Macだと[Command]+[Option]+[I]かな?
Chromeブラウザ内蔵デベロッパーツールが起動する。

使用していないCSSを削除してください 4
ここで、[Ctrl]+[Shift]+[p]を押す。Macの場合は[Command]+[Shift]+[p]かな?
小窓がポップアップするのでテキストボックスにshow coverageと入力する。部分一致で候補が表示されるので実際にはcoverとかで良い。2022年12月2日追記: その後show coverageは日本語表対応になったので「カバレッジを表示」を探してください。show coverageでは候補が出なくなっていると思われます。

使用していないCSSを削除してください 5
「[Drawer] Show Coverage」という候補が表示されるのでそれをクリックする。2022年12月2日追記: その後、日本語対応になったので「カバレッジを表示」という候補をクリックしてください。

使用していないCSSを削除してください 6
下部にドロワーが表示されるというかウィンドウが分割されたようになって、Coverageタブが選択された状態になる。
その中央の[]をクリックする。

使用していないCSSを削除してください 7
そのページで読み込まれているJava scriptやCSSのファイルがリストされ、そのファイルで使用されているコードの割合が表示される。上の画像では赤枠で囲ったsemantic.min.cssがSemantic UIのCSSファイルだが、約630KBのファイルを読み込んで、そのファイルのCSSコードの内ページ表示で使用されているのが僅か2.2%であることを示している。つまり630KBも読み込んで97.8%は無駄になっている。これは指摘されても仕方ない。(本当はもう少し多くのコードが使われる)
このリストの中から目的のファイルの行をクリックする。(上の画像だと赤枠で囲ったsemantic.min.cssをクリック)

使用していないCSSを削除してください 8
ファイルを(ダブル)クリックすると上側のConsoleタブが選択されていたところがSourcesタブに切り替わる。(基本的には自動の筈だが切り替わらない場合は手動で[Sources]をクリック)
クリックしたファイルのコードが表示される。改行,余分な空白/タブが削除されたコンパクト化されているcss,jsファイルもフォーマット化されてわかりやすく表示される。
使用中のコードと未使用のコードが色分けされるので青緑の帯が付いた(使用されている)コードをコピーしてエディタなどに貼る。繰り返して使用中のコードを全て抜き出す。

別ページでも同様に繰り返して使用中のコードを抜き出す。普通のWordPressのブログならトップベージ、固定ページ、投稿ページ、記事のリストのページのようにページの種類ごとに各1ページずつから抜き出せば良いかと。ただし、テーブルだとかアイコンだとか特定のページでしか使用していないコードは別途抜き出しの必要も。
ある程度名の知れたフレームワークならCSSコードが系統で分けてあるはずなので整理しながら重複しないように抜き出せる筈。

これで、一応ページの表示そのものに使用されているコードだけは抜き出せたが、それだけではちょっと足りない筈。
元ファイルと比較する方が良い。CSSにに慣れてる人なら先の使用されていないCSSコードの中に必要なコードが混じっていることに気付くかもなので、使用されていないCSSコードに分類されていてもコピーしておけば良い。
元ファイルと比較した場合は元ファイルの分類別コメントをコピーしておく方が後の編集がラクになる。
@media hogeとかイベント・アニメーション関連などはモレ注意。大抵は使用中コードの青緑でマークされている前後に隣接して存在するのであるていどは判るようになっている。

使用中のコードを抜き出して編集したファイルをsemantic-subset.cssなどのファイル名で保存する。
semantic-subset.cssからコメント,改行,タブ,余計な空白を除去してsemantic-subset.min.cssを出力する。
必要に応じてsemantic-subset.min.cssをBrotli圧縮またはGzip圧縮する。(ウェブサーバが静的Brotli/Gzip圧縮対応の場合)
HTMLファイルのHTMLヘッダのCSSファイルのpath+ファイル名を変更する。WordPressならテーマのディレクトリにあるheader.phpと必要に応じてfunctions.phpでファイルの指定を変更する。

JavascriptもCSSの場合と一応同じ方法が使える。ただし、ページ表示しただけでは表示で使用したコードだけしかマークされない。Semantic UIのサイドバーであればトグルボタンを少なくとも2回押してスライドオープン、クローズを実行しなくては必用なコードと不要なコードが判らない。動作に必要なコードを削ってしまうとJavascriptの実行エラーで他の必要なJavascriptまで動かなくなると困った事態になるかもしれない。Semantic UIのJavascriptは1つの巨大なファイルに複数の機能別に関数が分かれて入っているので使用する機能の関数だけまるごと抜き出す方が無難。Javascriptの巨大なコードがスラスラ理解できる人はさらに不要なコードを取り除いてファイルをダイエットさせれば良いかなと思う。

Semantic UI 2.4.2のdist/semantic.jsは以下の様になっている。
site: 11-498行
form: 499-2205行
accordion: 2206-2818行
checkbox: 2819-3651行
dimmer: 3652-4385行
dropdown: 4386-9047行
modal: 9048-10083行
nag: 10084-10591行
popup: 10592-12124行
progress: 12125-13056行
rating: 13056-13565行
search: 13566-15071行
shape: 15071-15993行
sidebar: 15994-17027行
sticky: 17028-17987行
tab: 17988-18940行
transition: 18940-20036行
api: 20037-21204行
visibility: 21205-22515行

たとえば、「がとらぼ」のスマホ用ページならSemantic UIのJavaScriptはサイドバーしか使っていないのでサイドバー関連の15994〜17027行だけ抜き出してsemantic-subset.jsのようなファイル名で保存する。
semantic-subset.jsからコメント,改行,タブ,余計な空白を除去してsemantic-subset.min.jsを出力する。
必要に応じてsemantic-subset.min.jsをBrotli圧縮またはGzip圧縮する。(ウェブサーバが静的Brotli/Gzip圧縮対応の場合) HTMLファイルのHTMLヘッダのJavascriptファイルのpath+ファイル名を変更する。WordPressならテーマのディレクトリにあるheader.phpと必要に応じてfunctions.phpでファイルの指定を変更する。

これで、ファイルサイズ自体が大幅に小さくなる。 変更前のsemantic.jsは737KB。余計な空白・コメント・改行の無いsemantic.min.jsが275KB。
semantic.jsからSemantic UIのサイドバー機能のコードだけをまるごと抜き出したファイルサイズは約34KB。余計な空白・コメント・改行の無くしたsemantic-subset.min.jsが13KB。ファイルサイズでは約5%になった。
この小さくなったファイルの内、ページ表示時に使うコードは8.5%で91.5%が無駄なコードとして指摘される。サイドバーのオープン・クローズを実行した場合、使用コードが80.1%になり未使用コードが19.9%になる。結構使われるのよね。
でも、正直なところ、サイドバーのスライドによるオープン・クローズ程度なら1KBも要らないので自分で作っちゃった方が圧倒的にコンパクトな筈。

使用していないCSSを削除してください 9
CSSとJavascriptのダイエットが完了したのでもう一度PageSpeed Insightsで計測してみた。ダイエット前のスコアが52で、ダイエット後が64なのでスコアが12上昇したことになる。また、「使用していない CSS を削除してください」の指摘は無くなり、「使用していない JavaScript の削除」の指摘対象からは今回スリムになったsemantic-subset.min.jsは消えている。しかし、残り3つの指摘されているファイルがあるので、これもなんらかの対応が必用。

ちなみに、他に指摘されている改善可能な項目は「適切なサイズの画像」「次世代フォーマットでの画像の配信」「効率的な画像フォーマット」。
「適切なサイズの画像」はモバイル端末には画面サイズに合わせて小さい画像を出せというやつ。pictureタグを使えば指摘されない。WordPressのブログ等ではメディアの扱いをWordPressまかせにしていれば指摘されない部分。
ただし、素のWordPressでは次世代フォーマットの画像を扱えないので「次世代フォーマットでの画像の配信」で指摘を食らう。
「がとらぼ」では画像をWordPressまかせでなく独自管理にしていてimgタグを使っている。画像を複数サイズ用意するのが面倒なのでpictureタグは使っていない。その代わり基本出力が次世代フォーマット画像のWebP。WebP非対応ブラウザにはJpegかPNGを送る。これはNginxまかせ。
基本がWebPなら「次世代フォーマットでの画像の配信」の指摘は喰らわない筈なのに指摘されてるのはAliExpressの商品画像のせい。これは手出しできない他所のウェブサイトなのでどうしようもない。「効率的な画像フォーマット」もAliExpressの同じ画像が指摘を受けている。迷惑な話。

Up