【実践シェルスクリプト講座 第4回】攻撃者を秒でブロック!ログ解析による「SSH総当たり攻撃」自動防御システム

【実践シェルスクリプト講座 第4回】あなたのサーバーは狙われている!「SSH総当たり攻撃」を自動で撃退せよ

こんにちは!「リナックス先生」です。
前回は、面倒なユーザー作成を一瞬で終わらせる「自動化スクリプト」を作成しました。
これでサーバー管理が随分と楽になったはずですが…コウ君、その後サーバーのログは見てみた?

コウ君

先生…!見ました!見てしまいました…。
/var/log/secure をなんとなく眺めていたら、知らないIPアドレスから「Failed password」のエラーが大量に出ているんです!
これって、もしかしてハッキングされかけてますか!?(ガクブル)

リナックス先生

落ち着いて。SSHポート(22番)を公開しているサーバーなら、それは「日常風景」よ。
世界中の攻撃ボットが、24時間休まずに総当たり攻撃(ブルートフォースアタック)を仕掛けてきているの。
パスワードが強固ならすぐには破られないけれど、ログが汚れるし、サーバーの負荷にもなるわ。
今回は、この「不届き者」を自動検知して、ファイアウォールで門前払いする「自動防衛システム」を作りましょう!

「実践シェルスクリプト講座」第4回のテーマは、「セキュリティの自動化」です。
ログ解析の王道ツール awk で攻撃者を特定し、現代Linuxの標準ファイアウォールである firewalld を操作して、悪意あるIPアドレスをブラックリストに放り込むスクリプトを作成します。

本講座のカリキュラム(全5回)

いよいよ後半戦、セキュリティ編です。

  1. サーバー停止の恐怖から解放!「ディスク容量監視」と「ログ自動整理」の完全自動化【完了】
  2. データ消失をゼロにする!「堅牢バックアップ」と「Slack通知」の構築【完了】
  3. 手作業を撲滅せよ!「ユーザー一括作成」と「SSH鍵配布」の自動化スクリプト【完了】
  4. 【今回】攻撃者を秒でブロック!ログ解析による「SSH総当たり攻撃」自動防御システム
  5. プロの品質へ!スクリプトの「安全性向上(デバッグ)」と「トラブルシューティング」

1. 敵を知る:攻撃の痕跡「secureログ」を読む

まずは、敵がどこに痕跡を残しているかを知る必要があります。
RHEL系(AlmaLinux, CentOS)のLinuxでは、認証に関するログは /var/log/secure に記録されます(Ubuntuなどは /var/log/auth.log です)。

実際に、以下のコマンドで「ログイン失敗」の記録を見てみましょう。

[root@localhost ~]# grep "Failed password" /var/log/secure | tail -5
Jan 25 10:00:01 server sshd[12345]: Failed password for root from 192.0.2.100 port 54321 ssh2
Jan 25 10:00:03 server sshd[12345]: Failed password for invalid user admin from 192.0.2.100 port 54322 ssh2
...

このように、「誰が(rootやadmin)」「どこから(192.0.2.100)」失敗したかが記録されています。
これを目視でチェックして手動でブロックするのは不可能です。
そこで、スクリプトの出番です。

2. ログ解析の魔法「awk」と「uniq」

スクリプトを作る前に、コマンドラインで「攻撃回数ランキング」を作ってみましょう。
これがスクリプトの心臓部になります。

ステップごとの解説

1. 失敗ログだけを抜き出す

grep "Failed password" /var/log/secure

2. IPアドレスの部分だけを抜き出す
ログの形式は Failed password for ... from 192.0.2.100 port ... となっています。
from の後ろにあるIPアドレスを取り出すには、テキスト処理が得意な grep -oE(正規表現抽出)を使うのが最も確実です。

# [0-9]{1,3} は「1〜3桁の数字」を意味する正規表現
grep -oE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"

3. 集計して多い順に並べる

... | sort | uniq -c | sort -nr
  • sort: 同じIPを隣り合わせにする
  • uniq -c: 重複している行をまとめて、回数をカウントする
  • sort -nr: 回数(Number)の逆順(Reverse)で並べ替える

完成したコマンドライン

[root@localhost ~]# grep "Failed password" /var/log/secure | grep -oE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" | sort | uniq -c | sort -nr | head -5
   150 192.0.2.100
    45 203.0.113.10
    12 198.51.100.5

出ました!犯人は 192.0.2.100 ですね(150回も間違えています)。
これを自動的にファイアウォールに登録するのが今回の目標です。

3. 鉄壁の守護神「block_attacker.sh」の実装

それでは、自動ブロックを行うスクリプトを作成します。
AlmaLinux 9など現代のLinuxでは、firewalld を使って制御するのが一般的です。

スクリプトの仕様

  1. /var/log/secure を解析し、過去5000行から失敗履歴を探す。
  2. 同じIPからの失敗が「5回」を超えていたら攻撃とみなす。
  3. 【重要】そのIPを自身のホワイトリスト(除外リスト)と照合する。
  4. Firewalldの「dropゾーン」にIPを追加して接続を拒否する。
  5. 結果をログに残す(Slack通知を入れてもOK)。

スクリプト作成:block_attacker.sh

vim block_attacker.sh を作成します。

#!/bin/bash

# --- 安全設定 ---
# set -u : 未定義変数エラーチェック
set -u

# ==========================================
# 設定エリア
# ==========================================
LOG_FILE="/var/log/secure"
BLOCK_LOG="/var/log/block_attacker.log"
# 許容する失敗回数
LIMIT=5
# 解析する過去のログ行数(全行読むと重いため)
READ_LINES=5000

# ホワイトリスト(正規表現)
# 自分のIPや社内ネットワーク、ローカルホストは絶対にブロックしない!
# 例: 127.0.0.1 または 192.168.1.xxx
WHITELIST="^127\.0\.0\.1$|^192\.168\.1\."

# ==========================================
# メイン処理
# ==========================================

# ログ出力関数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$BLOCK_LOG"
}

# 1. ログファイル確認
if [ ! -f "$LOG_FILE" ]; then
    log "ログファイルが見つかりません: $LOG_FILE"
    exit 1
fi

log "--- 解析開始 ---"

# 2. 攻撃者のIPリストを作成してループ処理
tail -n "$READ_LINES" "$LOG_FILE" \
| grep "Failed password" \
| grep -oE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" \
| sort | uniq -c \
| while read COUNT IP; do

    # カウント数が閾値未満なら何もしない
    if [ "$COUNT" -lt "$LIMIT" ]; then
        continue
    fi

    # 3. ホワイトリストチェック(最重要!)
    if [[ "$IP" =~ $WHITELIST ]]; then
        # 許可IPなのでスキップ
        continue
    fi

    # 4. 既にブロック済みかチェック
    # firewall-cmd --list-sources --zone=drop で現在ブロック中のIP一覧が取れる
    # grep -q で「見つかったら成功(0)」を返す
    if firewall-cmd --zone=drop --list-sources | grep -q "$IP"; then
        # 既に登録済みなのでスキップ
        continue
    fi

    # 5. ブロック実行!
    log "【検知】攻撃IPを検出: $IP (失敗回数: $COUNT)"
    
    # 即時反映(メモリ上に追加)
    firewall-cmd --zone=drop --add-source="$IP"
    # 永続化(再起動後も有効にする)
    firewall-cmd --permanent --zone=drop --add-source="$IP"
    
    if [ $? -eq 0 ]; then
        log "【ブロック成功】$IP をdropゾーンに追加しました。"
        # ★ここにSlack通知コマンド(第2回参照)を入れると完璧!
    else
        log "【エラー】$IP のブロックに失敗しました。"
    fi

done

log "--- 解析終了 ---"

⚠️ 最重要:ホワイトリストの設定を忘れずに!

このスクリプトは容赦なくブロックを行います。
もしあなたがパスワードを5回間違えたら、あなた自身がサーバーから締め出され、二度とログインできなくなります(いわゆるセルフBAN)。
WHITELIST 変数には、必ずあなたの会社の固定IPや、VPNのIP帯域などを記述してください。
もし固定IPがない場合は、一時的に閾値(LIMIT)を100回など大きくして様子を見るのが安全です。

4. Firewalldの「ゾーン」とは?

スクリプト内で登場した --zone=drop について補足します。
Firewalldには「信頼度」に応じた複数のゾーン(エリア)があります。

ゾーン名 挙動 用途
public デフォルト。許可した通信以外は拒否(reject)。 通常のインターネット公開用
drop 全ての通信を無視して破棄(drop)。相手に返事すらしない。 攻撃者・ブラックリスト用
trusted 全ての通信を許可。 信頼できる社内ネットワーク用

攻撃者のIPを drop ゾーンに追加するということは、サーバーがそのIPに対して「無(Null)」になるということです。
相手からはサーバーが存在しないかのように見えるため、最も効果的な防御手段となります。

5. 運用とメンテナンス:ブロック解除方法

万が一、間違って正常なIPをブロックしてしまった場合は、手動で解除する必要があります。
慌てず以下のコマンドを実行しましょう。

ブロック中のIP一覧を確認

[root@localhost ~]# firewall-cmd --zone=drop --list-sources
192.0.2.100 203.0.113.10

ブロック解除(許可)

# 一時的な設定からの削除(即時反映)
[root@localhost ~]# firewall-cmd --zone=drop --remove-source=192.0.2.100
# 永続的な設定からの削除(次回起動時用)
[root@localhost ~]# firewall-cmd --permanent --zone=drop --remove-source=192.0.2.100

6. 既存ツール「Fail2Ban」との違い

詳しい方なら、「それ、Fail2Banというツールを入れればいいのでは?」と思ったかもしれません。
正解です!実務では Fail2Ban という素晴らしいオープンソースソフトウェアを使うのが一般的です。

しかし、今回あえてスクリプトを自作したのには理由があります。

  1. 仕組みの理解: ツールに頼りきりだと、「なぜブロックされたか」「ログのどこを見ればいいか」がわからなくなります。
  2. カスタマイズ性: 自作スクリプトなら、「ブロックしたらSlackに通知」「社内のDBにIPを登録」といった独自の連携が自由自在です。
  3. 学習効果: ログ解析(grep/awk)とシステム制御(firewall-cmd)は、インフラエンジニアの必須スキルセットそのものです。

このスクリプトが書けるようになれば、SSHだけでなく、Webサーバー(Nginx/Apache)への攻撃や、アプリケーションのエラー検知にも応用が効くようになります。

まとめ:自動防御で枕を高くして寝よう

今回は、サーバーを攻撃から守る「自動防衛システム」を構築しました。

技術要素 解説
grep -oE 正規表現を使ってIPアドレスだけを抽出するテクニック
uniq -c 重複行を数えてランキングを作るコマンド
firewall-cmd Linuxのファイアウォールを操作するコマンド
--zone=drop 攻撃者をブラックリストに入れるための設定エリア

これをCronに仕込んでおけば(例:10分に1回実行)、あなたが寝ている間もスクリプトが監視を続け、怪しいIPを次々とブロックしてくれます。
まさに「サーバーの守護神」ですね。

次回予告:プロはここを見る!トラブルシューティングと品質向上

全5回の講座も、いよいよ次回が最終回です。
これまでに作った4つのスクリプトは便利ですが、プロの現場で運用するにはまだ少し「甘い」部分があります。

次回は、
「スクリプトが動かない時のデバッグ方法」
「安全性を高めるコーディング規約」
「Cronで動かない”あるある”問題の解決」
など、ワンランク上のシェルスクリプト技術を総まとめします。

リナックス先生

今回のスクリプトは強力だから、テストするときは必ず 「自分をブロックしないか」 を慎重に確認してね。
もし締め出されたら、VPSのコンソール機能(Webブラウザから操作できる画面)から入って解除するのよ!

▼万が一締め出されてもコンソールから復旧可能!推奨VPS

【2026年最新】Linuxサーバー構築におすすめのVPS比較3選!現役エンジニアが速度とコスパで厳選
Linuxの勉強、まだ「自分のPC」でやって消耗していませんか?「Linuxを覚えたいけど、環境構築でエラーが出て先に進めない…」「VirtualBoxを入れたらパソコンが重くなった…」これは、Linux学習を始める9割の人がぶつかる壁です...

コメント