監視・通知

VPSサーバーのセキュリティログを確認して攻撃を検出する方法

セキュリティ監査 ログ分析 Fail2Ban

VPSサーバーのセキュリティログを
確認して攻撃を検出する方法

VPSを運用していると、ポートスキャン、WordPress脆弱性スキャン、RCE攻撃など、日常的にさまざまな攻撃を受けます。
ログを定期的に確認し、防御が正しく機能しているか検証することが重要です。
本記事では、実際のサーバーログを使って攻撃の検出方法と対処法を解説します。

こんな人向けの記事です

  • VPSサーバーを運用していて、攻撃を受けていないか確認したい
  • Nginxアクセスログ・エラーログの読み方を知りたい
  • UFWやFail2Banのログから攻撃状況を把握したい
  • ポートスキャンやWebスキャンへの対処法を知りたい

確認すべきログファイル一覧

サーバーのセキュリティ状態を把握するために、以下のログを定期的に確認します。

ログファイル内容確認頻度
/var/log/nginx/access.log全HTTPアクセス記録月次
/var/log/nginx/error.logNginxエラー(Rate Limit超過等)月次
/var/log/kern.logUFWのブロックログ月次
/var/log/auth.logSSH認証の成功・失敗月次
DjangoセキュリティログXSS/SQLi等の攻撃検知月次

Nginxアクセスログの分析

IP別アクセス数ランキング

まず、どのIPから大量アクセスがあるかを確認します。

コマンド
cat /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

出力例:

   3199 185.177.72.52
   2242 185.177.72.38
   1639 185.177.72.60
    644 150.31.5.3      ← 自社IP(正常)
    476 68.221.64.54
    354 40.80.90.214
注意: 同一ネットワーク帯(例: 185.177.72.x)から複数IPで大量アクセスがある場合、組織的なスキャンボットの可能性が高いです。

HTTPステータスコード別集計

404が大量に発生していれば、存在しないパスへのスキャンを受けています。

コマンド
cat /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -rn
  10712 404    ← 大量のスキャン
    392 444    ← Nginxが接続を切断(不明ドメイン等)
    257 503    ← Rate Limit超過
    196 403    ← アクセス拒否
    117 200    ← 正常アクセス

攻撃パターンの特定

よく見られる攻撃パターンをアクセスログから抽出します。

コマンド
grep -E "(admin|wp-login|\.env|phpinfo|\.php|shell|passwd|\.git)" /var/log/nginx/access.log | tail -20

WordPress脆弱性スキャン

WordPressを使っていなくても、以下のようなスキャンが日常的に来ます。

104.211.96.131 - "GET /wp-login.php HTTP/1.1" 404
104.211.96.131 - "GET /wp-admin/images/ HTTP/1.1" 404
104.211.96.131 - "GET /xmlrpc.php HTTP/1.1" 404
104.211.96.131 - "GET /phpMyAdmin/ HTTP/1.1" 404

環境ファイル・機密情報の探索

185.177.72.52 - "GET /.env HTTP/1.1" 404
185.177.72.52 - "GET /node_modules/.env HTTP/1.1" 404
185.177.72.52 - "GET /private.key HTTP/1.1" 404
185.177.72.52 - "GET /secrets.yml HTTP/1.1" 404
185.177.72.52 - "GET /settings.py HTTP/1.1" 404

RCE(リモートコード実行)攻撃

# Apache パストラバーサル (CVE-2021-41773)
81.17.103.232 - "POST /cgi-bin/.%2e/.%2e/.%2e/bin/sh HTTP/1.1" 400

# PHP RCE
217.217.251.46 - "POST /hello.world?auto_prepend_file=php://input HTTP/1.1" 444

# XDebug RCE
79.124.40.174 - "GET /?XDEBUG_SESSION_START=phpstorm HTTP/1.1" 444

# Exchange ProxyShell (CVE-2021-34473)
135.237.126.114 - "GET /autodiscover/autodiscover.json?@zdi/Powershell HTTP/1.1" 404
ポイント: これらの攻撃は全て404(存在しない)や444(Nginxが切断)で応答しています。Djangoアプリケーションには到達していないため、防御は正常に機能しています。

Nginxエラーログの分析

エラーログではRate Limit超過やSSLエラーを確認できます。

コマンド
tail -100 /var/log/nginx/error.log

Rate Limit超過

[error] limiting requests, excess: 20.490 by zone "general",
  client: 20.214.159.60, request: "GET /wp-content/index.php HTTP/1.1"

攻撃者がRate Limitを超過してブロックされている記録です。zone "general" は一般的なレート制限、zone "login" はログインページ用のより厳しい制限です。

SSL ハンドシェイクエラー

[crit] SSL_do_handshake() failed
  (SSL: error:0A00006C:SSL routines::bad key share)
  client: 216.180.246.175

不正なSSLハンドシェイクを試みるスキャナーです。TLSバージョンや暗号スイートの互換性がない場合に発生し、接続は確立されません。

自社IPのRate Limit超過に注意

注意: 自社IPがRate Limitに引っかかることがあります。JavaScriptやCSSファイルが多いページ(SPAなど)を開くと、一度に大量のリクエストが発生するためです。自社IPはFail2Banのignoreipに追加しておきましょう。
/etc/fail2ban/jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 自社のIPアドレス
bantime = 3600
findtime = 600
maxretry = 3

UFWログでポートスキャンを検出

UFW(Uncomplicated Firewall)のログで、許可ポート以外へのアクセス試行を確認します。

コマンド
grep "UFW BLOCK" /var/log/kern.log | tail -30
[UFW BLOCK] IN=ens3 SRC=212.73.148.28 DST=219.94.232.146
  PROTO=TCP SPT=48029 DPT=49678 SYN
[UFW BLOCK] IN=ens3 SRC=79.124.62.134 DST=219.94.232.146
  PROTO=TCP SPT=57298 DPT=52829 SYN
[UFW BLOCK] IN=ens3 SRC=176.65.149.27 DST=219.94.232.146
  PROTO=TCP SPT=56251 DPT=38194 SYN

ログの読み方:

フィールド意味
SRC攻撃元IPアドレス
DSTターゲット(自サーバー)IP
DPTスキャンされたポート番号
SYNTCP SYNパケット(接続開始要求)
PROTOプロトコル(TCP/UDP)
ポイント: 全て「UFW BLOCK」なので、ファイアウォールで遮断されています。SYNパケットのみで接続は確立されていないため、サーバーへの侵入はありません。ポートスキャンはインターネットに公開されたサーバーでは日常的に発生するものです。

よくあるスキャン元

IP帯域種別
212.73.148.x組織的ポートスキャン(複数IPから同時にスキャン)
167.94.138.x / 167.94.146.xCensys(インターネットスキャンサービス)
79.124.62.x繰り返しスキャン(同一ポートを定期的にスキャン)
176.65.149.xSYNスキャン(高速ポートスキャン)
147.185.132.xGreyNoise系スキャナー

Fail2Banのステータス確認

Fail2Banが正常に動作し、攻撃IPをBANしているか確認します。

コマンド
# 全Jailのステータス
sudo fail2ban-client status

# 特定Jailの詳細
sudo fail2ban-client status nginx-limit-req
sudo fail2ban-client status nginx-botsearch
sudo fail2ban-client status django-security
sudo fail2ban-client status sshd
Status for the jail: nginx-botsearch
|- Filter
|  |- Currently failed:  1
|  |- Total failed:      7
|  `- File list:         /var/log/nginx/access.log
`- Actions
   |- Currently banned:  1
   |- Total banned:      1
   `- Banned IP list:    185.177.72.52

確認すべきポイント:

  • Currently banned — 現在BANされているIP数
  • Total banned — 累計BAN数
  • Banned IP list — BANされているIPの一覧

SSH認証ログの確認

不正なSSHログイン試行がないか確認します。

コマンド
# 認証成功の履歴
last -20

# 認証失敗の履歴
sudo lastb -10

# 詳細ログ
tail -50 /var/log/auth.log
ポイント: SSH を公開鍵認証のみ(パスワード認証無効)に設定し、非標準ポートを使用している場合、外部からの不正ログイン試行はほぼ0件になります。lastbの出力に自社IP以外が表示されなければ安全です。

侵入の形跡チェック

ログ確認に加えて、サーバー内部に侵入の形跡がないかもチェックします。

1. ログイン可能なユーザーの確認

# シェルが割り当てられたユーザー一覧
cat /etc/passwd | grep -v nologin | grep -v false

想定外のユーザーが追加されていないか確認します。

2. リスニングポートの確認

sudo ss -tlnp

意図しないポートでリッスンしているプロセスがないか確認します。

3. 不審なcronジョブの確認

# ユーザーのcrontab
crontab -l

# システムのcrontab
cat /etc/crontab
ls /etc/cron.d/

4. 不審なファイルの確認

# /tmp等に最近作成されたファイル
find /tmp /var/tmp /dev/shm -type f -newer /etc/passwd 2>/dev/null

# 想定外のPHPファイル(Webシェル等)
find / -name "*.php" -newer /etc/passwd -not -path "/proc/*" 2>/dev/null

発見した攻撃への対処法

大量スキャンボットのブロック

特定のIP帯域から大量スキャンがある場合、Nginxで直接ブロックします。

/etc/nginx/sites-available/your-site.com
server {
    listen 443 ssl;
    server_name your-site.com;

    # 悪意あるスキャナーのブロック
    deny 185.177.72.0/24;

    # ... 他の設定
}

設定後、Nginxをリロードします。

sudo nginx -t && sudo nginx -s reload

自社IPのFail2Ban除外

自社IPがRate Limitに引っかかってBANされないよう、ignoreipに追加します。

/etc/fail2ban/jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 あなたのIP
bantime = 3600
findtime = 600
maxretry = 3
# 設定変更後、Fail2Banを再起動
sudo systemctl restart fail2ban

# ignoreipが反映されたか確認
sudo fail2ban-client get nginx-limit-req ignoreip

pingの無効化

pingに応答するとスキャナーにサーバーの存在を知らせてしまいます。無効化するには:

# 一時的に無効化
sudo sysctl -w net.ipv4.icmp_echo_ignore_all=1

# 永続化(再起動後も有効)
echo "net.ipv4.icmp_echo_ignore_all=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

まとめ

確認項目コマンド正常な状態
IP別アクセス数awk + sort + uniq自社IP以外の大量アクセスがないこと
ステータスコードawk + sort + uniq404が大量でも全てスキャン(200で機密情報を返していないこと)
ポートスキャンgrep "UFW BLOCK" kern.log全て「UFW BLOCK」で遮断されていること
Fail2Banfail2ban-client statusJailが稼働中で攻撃IPがBANされていること
SSH認証last / lastb自社IP以外のログイン履歴がないこと
侵入の形跡ss -tlnp / crontab / find不審なポート・ジョブ・ファイルがないこと
重要: ログ確認は月次で定期的に実施しましょう。また、攻撃パターンは常に進化しています。Fail2BanやUFWのルールは定期的に見直し、新しい攻撃手法に対応できるよう更新してください。