さくらVPS SiteGuard のログで BLOCK と検知を見分ける

パーク24グループのタイムズカーを皮切りに、GMOインターネットがサイバー攻撃を受けた大規模なセキュリティ事件など、Webの不正アクセスがここ数週間で続けて表に出ている。

そのような週に、自分のさくらVPSに入っている SiteGuard Lite の直近ログをまとめて見てみた。並んでいたのは、設定ファイルや環境変数ファイルの名前を直接たたくリクエスト、ディレクトリを逆上ろうとするリクエスト、このサーバでは動いていない別プロダクト向けの攻撃、見慣れない HTTP メソッドだった。

確認した範囲では、判定は BLOCK だった。目的は、今はアプリの手前で止まっている通信が、もしすり抜けたときに広がらないよう、入口を減らすことに置いた。

環境は、さくらのVPS、RHEL系、Apache httpd、firewalld、PHP(php-fpm)、SiteGuard Lite。中では WordPress や EC-CUBE など、複数のサイトが同居している。以下のホスト名とIPは、すべて例である。

ログの読み方

1行から拾ったのは、次の4つだけだ。

  • いつ来たか
  • どの種のURLか(設定ファイル名、管理系のパス、異常に長いクエリ、など)
  • 判定が BLOCK か、検知だけで通しているか
  • 同じ送信元が、短時間に何件来ているか

BLOCK は、そのリクエストがアプリケーションまで届いていない、という意味だ。件数の多さは、盛んに探されているという兆候であって、侵入の証明ではない。

この記事では、止め方を次の3語で呼び分ける。

  • BLOCK … SiteGuard がアプリの手前で拒否する
  • 403 … Apache がリクエストを拒否する
  • DROP … firewalld がパケットを捨て、相手からは届かないように見える
ログ1行を、いつ、どのURLか、判定、同じ送信元の4つに分けた図。アドレスは例。
ログ1行から拾うのはこの4つ。アドレスとホスト名は例。

方針

本命は SiteGuard の公式シグネチャにする。IPの一覧は補助に置いた。送信元は毎日替わるので、一覧を人手で追い続けることを主対策にはしない。

実施したことは、ログに近いものから次の順だ。

  1. 公開しなくてよいファイルを閉じる
  2. 使っていないホスト名を、外から中身が見えない状態にする
  3. アプリを系列内のセキュリティリリースに乗せ、アプリの管理画面を作業用回線だけにする
  4. バージョン文字列を応答ヘッダから外す
  5. 同じ失敗を繰り返すIPを、しばらく自動で遠ざける
  6. OSのセキュリティ更新だけを、再起動なしで自動適用する
  7. 突出した送信元だけ、補助として DROP する
  8. SiteGuard の管理ポートを、作業用回線だけにする
リクエストが通る層。firewalld、SiteGuard、未知ホスト、許可IP、パッチ、アプリ。
大半は SiteGuard で止まる。firewalld は、突出した送信元への補助。

1. 出してしまっていた情報を閉じる

IPアドレス直打ちで、サーバ標準のドキュメントルートにある info.php が 200 を返していた。中身は phpinfo で、PHPの版、パス、読み込まれているモジュールが一覧になる。診断用に置いたまま残っていたので、ファイルを退避し、同じ場所は 403 にした。標準のドキュメントルート自体も、中身を見せない設定に変えた。

あわせて、各サイトの .env と web.config を、外からステータスコードだけ確認した。いずれも 403 か 404 で、本文は出ていなかった。ここは塞がっていることの確認で、追加の拒否は入れていない。

HTTPメソッドは、サイトに必要なものだけ残した。通常の閲覧やフォーム送信では使わないメソッドは、Apache側で拒否している。

サーバのIPを直打ちすると Forbidden と出るブラウザ画面。アドレスは隠してある。
IP直打ちは Forbidden。以前はここに PHP の内部情報が出ていた。

2. 使っていないサイトと、名前だけのホスト

動いていないサイトは、ドキュメントルート、バーチャルホスト、不要なデータベースごと退役させた。残すサイトのデータベースとユーザーは触っていない。

DNSのワイルドカードは残した。* がある限り、消した名前も、存在しないサブドメインも、このサーバへ名前解決される。そこで、知っているホスト以外の HTTPS は 403 にした。知らない名前が、サーバ標準の証明書で応答する状態を止めるためだ。

公開中のサイトは、作業の前後で 200 であることと、証明書の発行者・期限を確認した。

ワイルドカードDNSで名前は届き、知らないホストは403になる図。ホスト名は例。
名前は届く。実在するホストだけを開き、それ以外は 403。ホスト名は例。

3. アプリ側の入口

EC-CUBE は、系列内のセキュリティリリースへ上げた。対象は管理画面の多要素認証まわりだ。本番は短いメンテナンスに入れ、データベースを取り、公式差分を当て、スキーマを更新してからメンテナンスを解除した。バージョン表記、関連ファイル、フロントと管理ログインの応答を確認して完了にした。住所や帳票などのカスタマイズは残している。

WordPress は、本体もプラグインも、すでに当時の最新だった。追加したのは xmlrpc.phpの拒否だけだ。ピンバックや総当たりの通り道として残りやすいので、使っていなかったパスは 403 にした。

EC-CUBE の管理画面は、許可する接続元が空だった。ここへ作業用回線のIPだけを入れた。別の回線から入る日は、そのIPを足してキャッシュをクリアする。

認証なしで置いてあった作業用の一時PHPも、同じ回線だけに限定した。コマンドを実行するファイルではなかったが、内部のパスや作業の進み具合が見える。用が済んだら消す。

許可していない回線では、アプリの管理画面がアクセスできませんと表示される。
許可していない回線からは、アプリの管理画面は開かない。サイト名とアドレスは隠してある。
作業用回線からは、アプリのログイン画面が開く。
作業用回線からは、ログイン画面まで届く。

4. バージョンをヘッダに出さない

PHP は初期状態だと、応答ヘッダに X-Powered-By: PHP/x.x.x を付ける。expose_php=Offにして php-fpm を再読み込みすると、このヘッダが無くなる。画面の動作は変わらない。脆弱性そのものを塞ぐ設定ではなく、版の当たりを付けにくくする設定だ。

expose_php = Off

5. 繰り返しは fail2ban に任せる

fail2ban を入れ、ログ上で失敗や漁りが続くIPを、firewalld で一時的に DROP するようにした。有効にしたのは次の6つだ。

Jail見ているもの
sshdSSHのログイン失敗
apache-authBasic認証などの失敗
apache-badbots既知の悪質なクローラ
apache-noscript存在しないスクリプトへの漁り
apache-overflows異常に長いURLなど
recidive何度も遮断されたIPを、長めに遮断

作業用回線は ignoreip に入れ、自分の操作で自分を落とさないようにした。

副作用は、正規の利用者まで一時的に届かなくなることだ。会社やキャリアの出口IPは、無関係な人と共有されていることがある。導入後は fail2ban-client status で件数を見て、おかしい jail は条件を弱めるか外す。

01

🚪

失敗が少ない

まだ通す

02

⚠️

短時間に繰り返す

同じ送信元が続く

03

🔒

しばらく閉める

一時的に DROP

同じ送信元が短時間に失敗を重ねたら、しばらく玄関を閉める。

6. OSのセキュリティ更新だけ自動化する

dnf-automatic を入れ、セキュリティ更新だけ自動適用にした。カーネル更新のあとの再起動は自動にしない。全体を自動更新するより適用範囲は狭いが、意図しない再起動でサイトが落ちることを避けた。

7. よく来るIPは補助で落とす

直近のログで突出していた送信元だけ、SiteGuard の接続拒否と firewalld の DROP の両方に入れた。国単位の拒否は入れていない。海外からの正規アクセスがあるためだ。

これは初回の補助である。その後に同じアドレスがログへ残り続けても、BLOCK 済みなら、一件ずつ DROP 一覧へ写す作業はしていない。本命は公式シグネチャと、その自動更新のままにしてある。同じキャンペーンでも送信元はすぐ替わる。

公開されている悪評IPの一覧も、そのまま全面適用はしていない。古いアドレスや、クラウドの共有レンジで、正規の通信まで巻き込むことがある。自サーバのログで、明らかにスキャンと言えるものだけを手で足す、で足りている。

8. SiteGuardの管理ポートは作業用回線だけ

SiteGuard の管理画面は 9443番で待ち受けている。これを、作業用回線と localhost だけに開いた。それ以外からは接続がタイムアウトする。公開サイトの 80 番と 443 番はそのままだ。

この画面は、本番サイトの Let’s Encrypt とは別の証明書を使っている。IPを直指定して開くと、ブラウザは証明書の警告を出す。許可した回線から詳細へ進んで開けばよい。

外出先からは、SSHのローカル転送で届ける。

ssh -L 9443:127.0.0.1:9443 user@your-server

手元のブラウザでは https://127.0.0.1:9443/ を開く。警告は出やすい。作業用回線のIPが変わったら、firewalld の許可を更新する。この更新を忘れると、自分だけが入れなくなる。

許可していない回線からは、管理ポートへの接続がタイムアウトする画面。
許可していない回線からは、接続がタイムアウトする。
証明書の警告を超えたあとの、SiteGuard のログイン画面。
許可した回線では、証明書の警告を超えるとログイン画面になる。アドレスは隠してある。
ログイン後の SiteGuard 管理画面。ホスト名と送信元の一覧は隠してある。
ログイン後の管理画面。シグネチャの内訳だけが見える。

見送ったこと

次の3つは、検討したうえで見送った。

IPv6の追加の締め

このVPSには、当時 IPv6 アドレスが付いていなかった。DNSの AAAA は残している。名前は IPv6 に解決されるが、サーバは IPv6 では応答しない。アドレスを有効にする直前に、firewalld で SSH、HTTP、HTTPS 以外が閉じていることを確認すれば足りる、と判断した。

検知ログからの自動DROP

WAFがすでに拒否しているリクエストを、件数で firewalld へ流し込む仕組みだ。共有IPや、決済・APIのクラウドアドレスを巻き込みやすい。通知だけにする段階を飛ばして自動で落とすのは、今の量に対して副作用が大きい。

別の複数台のVPSと、攻撃IPを常時同期すること

近い時間に、同じキャンペーンが複数台へ来ることはある。ただ送信元は使い捨てが多く、誤って落としたときの影響が台数ぶん広がる。各台の SiteGuard に BLOCK を任せ、突出したものだけ、その台のログを見て手で足す方が扱いやすい。

今回で一区切り

入れたもの

  • 公開しなくてよいファイルと、未知のホストを閉じた
  • アプリを更新し、管理画面は作業用回線だけにした
  • fail2ban と、OSのセキュリティ更新を入れた
  • 管理ポートと、突出した送信元だけを補助で落とした

きっかけが来てから

そのとき足す

  • IPv6 を有効化する日
  • 封鎖後も、同じ送信元が異常に増える日
  • 本番の管理URLだけを突かれ続ける日
  • 別の複数台で、同じキャンペーンが同時に目立つ日
今回で一区切りにしたものと、きっかけが来てからでよいもの。

戻せるようにしておく

触る設定ファイルは、作業の前に日時付きでコピーした。アプリの更新では、データベースのダンプを別のディレクトリへ残した。

公開サイトは、変更のたびに次を確認する。

  • トップが 200 か
  • 証明書の発行者と期限
  • アプリの管理画面が、許可した回線からのみ開くか
  • 環境変数ファイルが 403 か 404 のままか

その後の見方

実装はここで一区切りにした。続けているのは、次の3つだ。

  • 作業用回線のIPが変わったら、SiteGuard の管理ポートと、アプリの管理画面の許可を更新する
  • SiteGuard の検知を、週に一度見る。新しい種類のURLが増えていないかを確認する
  • 本番の管理URLだけを狙われ続ける、DROP したあとも同じIPが異常に増える、実害が出る、のどれかが起きたら、そのとき足す

初回に突出していた送信元は入れてあり、それ以外は公式シグネチャの BLOCK に任せている。ログに多く出ている行を、そのたびに人手で写す作業はしていない。

チェックリスト

他のVPSへ持ち出すときの順は、こうなる。

  1. 確認したログの判定が BLOCK であることを見る
  2. phpinfo と、標準ドキュメントルートの公開を止める
  3. 環境変数ファイルが外から読めないことを、ステータスコードで確認する
  4. 使っていないホストを消し、ワイルドカード向けに、未知のホストを 403 にする
  5. アプリを系列内のセキュリティリリースへ上げ、使っていない xmlrpc.phpを拒否する
  6. アプリの管理画面に、許可するIPを入れる
  7. expose_php=Off にする
  8. fail2ban を入れ、作業用回線は対象から外す
  9. OSはセキュリティ更新のみ自動にし、再起動は手動のままにする
  10. 突出した送信元だけ、SiteGuard と firewalld に足す
  11. SiteGuard の管理ポートは、作業用回線と localhost だけにする
  12. 反映後に、公開サイトの応答と証明書を確認する

入口をゼロにはできない。新しい送信元、未知の攻撃、作業用回線の変化は残る。今回の効果は、偵察の材料と使っていない入口を減らし、すり抜けたときの範囲を、更新と権限の少なさで受け止めるところにある。