【実践シェルスクリプト講座 第4回】あなたのサーバーは狙われている!「SSH総当たり攻撃」を自動で撃退せよ
こんにちは!「リナックス先生」です。
前回は、面倒なユーザー作成を一瞬で終わらせる「自動化スクリプト」を作成しました。
これでサーバー管理が随分と楽になったはずですが…コウ君、その後サーバーのログは見てみた?
先生…!見ました!見てしまいました…。/var/log/secure をなんとなく眺めていたら、知らないIPアドレスから「Failed password」のエラーが大量に出ているんです!
これって、もしかしてハッキングされかけてますか!?(ガクブル)
落ち着いて。SSHポート(22番)を公開しているサーバーなら、それは「日常風景」よ。
世界中の攻撃ボットが、24時間休まずに総当たり攻撃(ブルートフォースアタック)を仕掛けてきているの。
パスワードが強固ならすぐには破られないけれど、ログが汚れるし、サーバーの負荷にもなるわ。
今回は、この「不届き者」を自動検知して、ファイアウォールで門前払いする「自動防衛システム」を作りましょう!
「実践シェルスクリプト講座」第4回のテーマは、「セキュリティの自動化」です。
ログ解析の王道ツール awk で攻撃者を特定し、現代Linuxの標準ファイアウォールである firewalld を操作して、悪意あるIPアドレスをブラックリストに放り込むスクリプトを作成します。
本講座のカリキュラム(全5回)
いよいよ後半戦、セキュリティ編です。
- サーバー停止の恐怖から解放!「ディスク容量監視」と「ログ自動整理」の完全自動化【完了】
- データ消失をゼロにする!「堅牢バックアップ」と「Slack通知」の構築【完了】
- 手作業を撲滅せよ!「ユーザー一括作成」と「SSH鍵配布」の自動化スクリプト【完了】
- 【今回】攻撃者を秒でブロック!ログ解析による「SSH総当たり攻撃」自動防御システム
- プロの品質へ!スクリプトの「安全性向上(デバッグ)」と「トラブルシューティング」
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 を使って制御するのが一般的です。
スクリプトの仕様
/var/log/secureを解析し、過去5000行から失敗履歴を探す。- 同じIPからの失敗が「5回」を超えていたら攻撃とみなす。
- 【重要】そのIPを自身のホワイトリスト(除外リスト)と照合する。
- Firewalldの「dropゾーン」にIPを追加して接続を拒否する。
- 結果をログに残す(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 という素晴らしいオープンソースソフトウェアを使うのが一般的です。
しかし、今回あえてスクリプトを自作したのには理由があります。
- 仕組みの理解: ツールに頼りきりだと、「なぜブロックされたか」「ログのどこを見ればいいか」がわからなくなります。
- カスタマイズ性: 自作スクリプトなら、「ブロックしたらSlackに通知」「社内のDBにIPを登録」といった独自の連携が自由自在です。
- 学習効果: ログ解析(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



コメント