SSH 認証ログの読み方:各失敗行の意味
ディストリビューションごとに失敗した SSH ログインがどこに記録されるか、メッセージの各形態の読み解き方、そして打ち間違いと一覧を回すボットネットの見分け方。
ログは実際どこにあるのか
最初につまずくのがここです。ディストリビューションによって違うからです。Debian と Ubuntu は認証イベントを /var/log/auth.log に書きます。RHEL、CentOS、AlmaLinux、Rocky、Fedora は /var/log/secure です。完全に journald へ移行したシステムではどちらのファイルも存在せず、すべてがジャーナルの中にあります。
移植性のある答えは journalctl で、systemd がある環境ならどこでも動きます:
# 移植性あり:sshd 自身のジャーナルをリアルタイムで追う
journalctl -u ssh -f # Debian/Ubuntu のユニット名
journalctl -u sshd -f # RHEL/Fedora のユニット名
# 直近 24 時間の失敗のみ
journalctl -u ssh --since -24h | grep -E 'Failed|Invalid user'
# まだファイルを書くディストリビューションでは:
grep -E 'Failed|Invalid user' /var/log/auth.log # Debian/Ubuntu
grep -E 'Failed|Invalid user' /var/log/secure # RHEL 系メッセージの形態を読み解く
sshd が出す失敗メッセージは少数で、それぞれ特定の意味を持ちます。次の 5 つを覚えれば、目にするもののほとんどを網羅できます:
- Failed password for <user> from <ip> port <n> ssh2 —— アカウントは存在し、パスワードが誤っていた。実在の利用者の打ち間違いか、有効なユーザー名を当てたボットのどちらかです。
- Failed password for invalid user <user> from <ip> —— アカウントが存在しない。ほぼ常に攻撃です。自分の利用者は自分のユーザー名を知っています。通常は別に「Invalid user」の行も伴います。
- Connection closed by authenticating user <user> <ip> port <n> [preauth] —— クライアントが認証の途中で諦めた。バナーだけ取りたかったスキャナーや、パスワード試行を拒否する鍵のみのサーバーでよく見られます。
- Disconnected from authenticating user root <ip> port <n> [preauth] —— root が禁止されたサーバーへの root ログイン試行。ここの量が多いのは、公開ホストで最もよくある特徴です。
- Maximum authentication attempts exceeded for <user> from <ip> —— クライアントが 1 接続内で MaxAuthTries に達した。多くの鍵を提示するエージェントであることも多いですが、見知らぬアドレスからならクレデンシャルを回すボットです。
攻撃と打ち間違いを見分ける
3 つの手がかりが両者を分けます。自動的に処置する前には 3 つとも揃っていることが望ましいです。
頻度と持続性。人は 1 分のうちに 2、3 回試し、その後は入れるか、あなたに電話してきます。ボットは何時間も一定の頻度を保ち、通宵、休みなく続けます。
アカウントの多様性。人は 1 つのアカウント、自分のものだけを試します。ボットは一覧を辿り、その大半は存在しません——まさに上の「invalid user」の特徴です。
送信元。自社の人間は既知のわずかなアドレスから接続します。攻撃はホスティングのレンジから、数百回ごとに別のアドレスへ移りながら、しばしば同じ 1 時間のうちに複数の国から届きます。
次のコマンドは直近 1 日の失敗を送信元アドレスでまとめ、それぞれがどのユーザー名を試したかを表示するので、3 つの手がかりが一度に見えます:
journalctl -u ssh --since -24h --no-pager |
grep -oE 'Failed password for (invalid user )?[^ ]+ from [0-9.]+' |
awk '{ ip = $NF; user = $(NF-2); count[ip]++; users[ip] = users[ip] " " user }
END { for (i in count) printf "%6d %-16s %s\n", count[i], i, users[i] }' |
sort -rn | head -15本当に警報を出すべき行
ログイン失敗はノイズです。そうでないメッセージが 1 つあり、それはダッシュボードではなく警報に値します:
Accepted password for <user> from <ip> —— パスワードによるログイン成功。サーバーが鍵のみであるべきなら、この行はそうなっていないことを意味し、設定に問題があります。パスワードを許可しているなら、同じレンジからの失敗の連続の直後に、見知らぬアドレスからこの行が出るのは、決して見たくない並びです。
あわせて見ておく価値があるのは、見覚えのない鍵フィンガープリントを伴う Accepted publickey と、持つべきでない利用者が開いた sudo セッションです。どちらも警報化のコストは低く、拒否の件数よりはるかに重要です。
# 直近 1 週間のすべての成功ログイン(方式と送信元つき)
journalctl -u ssh --since -7d --no-pager |
grep -E 'Accepted (password|publickey|keyboard-interactive)'読むことから遮断することへ
ログを手で読むのは診断であって防御ではありません。クエリを実行する頃には、攻撃はもう 1 週間続いています。何かを変えるのは、それを継続的に行い、しきい値をファイアウォール規則に変換することだけです。
素朴な実装はジャーナルを追い、送信元ごとに失敗を数え、nft を呼んでアドレスを遮断セットに加えます。動きはします。そして、この種のスクリプトが必ず出会う問題に出会います。セットは際限なく膨らみ、負荷でログが回ってイベントを取り逃がし、アップグレード後にユニットが静かに死に、1 件の誤判定が管理者を唯一の入口から締め出します。
SSH Protector はこのループをサービスとして実行します。統合された 1 つの nftables セット、遮断より常に優先されるホワイトリスト、起動時に復元される遮断、そしてローカルで下される判断——だからネットワークが持たないときにも持ちこたえます。読んでいるのは上で示したのと同じストリームであり、あなたから隠されているものはありません。
FAQ
- Linux で失敗した SSH ログインはどこに記録されますか?
- Debian と Ubuntu では /var/log/auth.log、RHEL、CentOS、AlmaLinux、Rocky、Fedora では /var/log/secure です。journald に完全に依存するシステムではどちらのファイルも存在せず、代わりにジャーナルを読みます:journalctl -u ssh(ディストリビューションのユニット名によっては -u sshd)。これはどこでも動きます。
- 「Failed password for invalid user」とは何を意味しますか?
- そのマシンに存在しないアカウントとして認証を試みた、という意味です。自分の利用者は自分のユーザー名を知っているので、この行はほぼ常に攻撃です——root、admin、ubuntu、test、git、oracle といった一般的な名前の一覧をボットが辿っています。量そのものは驚くことではなく、公開ホストならどこでも見られる背景水準です。
- なぜ root ログイン試行が何千件も見えるのですか?
- root はあらゆる攻撃一覧の最初のユーザー名であり、ボットにはそれがあなたのサーバーで禁止されていると知る術がないからです。PermitRootLogin を no か prohibit-password にしていれば成功はできませんが、試行に何のコストもかからないため止まることもありません。量への対処は送信元の遮断であって、ログインポリシーではありません。
- 成功した SSH ログインはどう確認しますか?
- 同じログで「Accepted」を検索します——Accepted publickey、Accepted password、Accepted keyboard-interactive のいずれかに続いてユーザー名、送信元アドレス、ポートが並びます。これこそ警報に値する行です。鍵のみであるべきサーバーでのパスワードログイン成功は設定ミスであり、失敗の連続のあと見知らぬアドレスから成功しているならインシデントです。
