新主机开服 5 小时被扫 67 条记录,之后 9 天一条都没有
每次有人问"新买的服务器要不要马上加固",评论区总会出现一个数字:24 小时内被扫描上万次,不加固就是裸奔。
我手上有一台 2026-10-26 开的华为云 ECS,Ubuntu 22.04,1.7G 内存,公网 IP 直连。开服当天就做了 ufw 默认拒绝、SSH 只留密钥、fail2ban 三件套。三个多月过去,我把 sshd 的 journal 和 ufw 的丢弃日志按天摊开数了一遍,得到的曲线和那个"上万次"的说法完全对不上:67 条异常记录,全部落在开服当天 09:30 到 14:33 这 5 个小时里,之后 9 天一条都没有。
这篇文章不讲"要加固"这种正确的废话,只讲三件能验证的事:怎么自己量、量出来的数为什么会骗人、以及开服那天真正值得动手的地方在哪。
一、先明确观测点,否则数字没有意义
同一批扫描流量,在不同的位置看到的东西完全不同。这台机器上有三个位置能留下痕迹:
| 观测点 | 能看到什么 | 看不到什么 |
|---|---|---|
| 云平台安全组 | 所有被策略拒绝的包(在平台侧计数) | 主机内部任何状态,日志不在机器上 |
| ufw(netfilter) | 到达网卡、被主机防火墙丢弃的包 | 安全组已经丢掉的包,一个字节都到不了这里 |
| sshd 进程 | TCP 建连之后的应用层行为(认证、KEX) | 没连上的 SYN、被防火墙丢掉的包 |
所以"被扫了多少次"这个问题,答案取决于你问的是哪一层。我下面给的数,全部来自第三层和第二层,也就是主机自己记得的部分。这一点必须先说清楚,否则后面所有结论都会被误读。
二、实测:67 条记录,5 小时,16 个 IP
先看时间分布。这条命令是把所有"非正常登录"的行按日期归并:
# 按天统计 sshd 的异常行,先确认"从哪天开始、到哪天结束"
journalctl -u ssh --no-pager -o short-iso \
| grep -E 'kex_exchange_identification|Connection closed by|Invalid user|Failed password' \
| cut -c1-10 | sort | uniq -c
输出只有一行:
67 2026-10-26
这台机器的 journal 是持久化的,最早一条能追到 7 月 31 日,所以"后面没有"不是被轮转吃掉了,是真的没有。
再看是谁来的:
# 按源 IP 归并。注意一次失败连接常留两行日志,这里的计数是"行"不是"连接"
journalctl -u ssh --no-pager \
| grep -oE 'Connection closed by (authenticating user [a-z]+ )?[0-9.]+' \
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' \
| sort | uniq -c | sort -rn | head -20
结果是 16 个不同的源地址,最多的是 195.178.110.232,出现 6 次,其中 5 次是这种形态:
Oct 26 13:18:30 hcss-ecs-7bdb sshd[8040]: Connection closed by authenticating user root 195.178.110.232 port 36408 [preauth]
[preauth] 说明它连认证阶段都没走完就断了。另外还有一批是这样的:
Oct 26 09:39:32 hcss-ecs-7bdb sshd[7687]: error: kex_exchange_identification: banner line contains invalid characters
这是扫描器直接把 HTTP 请求打到了 22 端口,sshd 等着收 SSH 版本号,收到的却是 GET / HTTP/1.1,于是报 banner 非法。这类流量在日志里根本不出现 IP,只有 error 行。
这里就是第一个陷阱:67 是日志行数,按 IP 归并后只有 28 行带源地址,16 个 IP。一次探测往往同时留下"kex 报错"和"Connection closed"两行,所以真实连接尝试大概在 30 次上下。把 67 当成"被攻击 67 次"是虚高,把 28 当成总数是虚低。
同一时间段,再看第二层,ufw 拦下的包:
# 按目标端口统计被丢弃的包,顺便看看扫描器最想敲哪个门
sudo zgrep -h 'UFW BLOCK' /var/log/ufw.log* \
| grep -oE 'DPT=[0-9]+' | sort | uniq -c | sort -rn | head -10
41 DPT=3389
2 DPT=21
2 DPT=20
1 DPT=443
一共 46 个包。41 个打 3389(Windows 远程桌面),剩下是 FTP 的 20/21。这台是 Linux,从来没开过 RDP,但扫描器不知道,它按 IP 段批量扫常见端口,3389 的命中率最高,所以量最大。
有意思的是那 1 个 443:443 明明在 ufw 的放行列表里,为什么会被记成 BLOCK?看原始行就明白了:
[UFW BLOCK] ... PROTO=TCP SPT=61226 DPT=443 WINDOW=1200 RES=0x00 RST URGP=0
RST 而不是 SYN。这是一个不属于任何已建立连接的复位包,ufw 的放行规则接的是新连接,这种游离包匹配不上,落到默认 deny 上就记一条。同理,同一个 46.151.178.14 在 10-29 和 11-01 各留了一条一样的记录——并不是完全没人来敲门,是没人再来敲 22。
三、为什么"0 次失败密码"和"0 次封禁"都不代表安全
这台机器上有一条命令的输出很容易让人误判:
journalctl -u ssh --no-pager | grep -c 'Failed password'
返回 0。而 fail2ban 的状态是:
|- Filter
| |- Currently failed: 1
| |- Total failed: 1
`- Actions
|- Currently banned: 0
|- Total banned: 0
三个多月,累计失败 1 次,封禁 0 次。如果只看这两个数,结论会是"我这机器没人攻击"。真实原因是另一回事:
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|maxauthtries|logingracetime)'
permitrootlogin without-password
passwordauthentication no
maxauthtries 4
logingracetime 30
密码认证是关的。攻击者连"输密码"这一步都到不了——sshd 在密钥交换之后直接告诉对方可用认证方式是 publickey,对方要么放弃(留下 Connection closed ... [preauth]),要么硬发密码(直接协议层拒绝,不产生 Failed password 行)。fail2ban 抓的是 Failed password 这类模式,没有密码尝试,它就永远显示 0。 这不是它失灵,是它的输入没了。
这也解释了一个常见困惑:为什么装了 fail2ban 之后感觉"没起作用"。要么过滤器的输入被关掉了,要么攻击根本没走到那一层。要判断 fail2ban 是否真的在工作,别看封禁数,看它的过滤器有没有读到行:
# 确认 backend 走的是 systemd journal,且 jail 在监听正确的单元
sudo fail2ban-client status sshd
sudo fail2ban-client get sshd logpath
sudo journalctl -u fail2ban -n 30 --no-pager
这台机器上的配置是这样,backend = systemd 是 Ubuntu 22.04 上的关键项(默认的 /var/log/auth.log 在部分镜像里可能不存在或被 rsyslog 关掉):
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
backend = systemd
[sshd]
enabled = true
backend = systemd
改完 sudo systemctl restart fail2ban,再用 fail2ban-client status sshd 看 Journal matches 那一行,确认是 _SYSTEMD_UNIT=sshd.service。如果这里是空的,规则写得再漂亮也不会触发。
四、报错、成因与处理对照
下面这些是我在这台机器上真实撞到过的,按"看到什么 → 为什么 → 怎么办"排:
| 现象 | 原因 | 处理 |
|---|---|---|
grep -c 'Failed password' 返回 0,脚本里带 set -e 直接退出 |
grep 无匹配时退出码是 1,不是 0 | 用 grep -c ... || true,或把结果放进 $( ) 里赋值,别让退出码冒泡 |
fail2ban Total failed: 1 长期不动 |
密码认证已关闭,攻击者不产生 Failed password,过滤器没有输入 |
用 kex_exchange_identification 或 preauth 计数作为补充口径;或改 fail2ban 的 failregex 覆盖 preauth 断开 |
ufw status 显示 Logging: on (low),但 ufw.log 只有一行 |
low 级别只记部分被丢弃的包,且 logrotate 会切走历史 | 统计要看 /var/log/ufw.log*,用 zgrep 一并扫;排查期临时调 ufw logging medium,事后调回 |
443 明明放行,ufw.log 里却有 DPT=443 的 BLOCK |
包带 RST 而非 SYN,不属于新连接,匹配不上放行规则 |
属正常现象,不用为它加规则;只要确认没有业务端口被误拦即可 |
journalctl -u ssh 只有几百行,以为日志丢了 |
主机日志量本来就小,加上轮转;Storage=persistent 才落盘 |
grep Storage /etc/systemd/journald.conf,必要时 persistent 并给 SystemMaxUse 上限 |
sshd -T 输出里 permitrootlogin 仍是 yes |
改动写进了 sshd_config 主文件,被 sshd_config.d/*.conf 或 Include 覆盖 |
用 sshd -T 看生效值,不要看配置文件里写了什么 |
最后一条尤其值得记:sshd -T 是唯一可信的"当前生效配置",改完必须用它复核,而不是重读自己刚写的文件。
五、那么开服当天到底该做什么
对着上面这组数,我的结论是:不要追"被扫了多少次"这个数字,它既不可靠也不可行动。 该做的是把暴露面收到最小,然后保证自己有办法看见变化。四件事,按顺序:
第一,端口只留必须的。 默认拒绝入站,逐条放行:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw --force enable
sudo ufw status numbered
注意 Docker 的 -p 会绕过 ufw 直接写 iptables 的 DOCKER 链,这条在另一篇文章里单独写过,这里只提醒一句:容器端口映射必须在云平台安全组层面收口,别指望 ufw。
第二,SSH 只留密钥。 顺序很重要——先在新开的会话里确认密钥能登、sudo -n true 能过,再关密码登录,否则容易把自己锁在外面:
# /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin prohibit-password
PasswordAuthentication no
KbdInteractiveAuthentication no
MaxAuthTries 4
LoginGraceTime 30
sudo sshd -t && sudo systemctl reload ssh
# 另开一个终端验证能登上来之后,再继续
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|maxauthtries)'
第三,让日志能被复查。 这次能得出结论,靠的是 journal 持久化和 ufw 日志没被关掉。排查期把 ufw 日志级别提到 medium,看完调回 low,否则一条中等强度的扫描就能把磁盘写满——这跟 Docker 日志撑满磁盘是同一类问题,只是来源不同。
第四,别把 fail2ban 当主要防线。 它的价值是压掉持续爆破的噪音,不是挡住扫描。密码认证关掉之后,它对 SSH 的作用基本就没了;真要防爆破,密钥 + 端口收口 + 云平台安全组白名单,三件的收益都远大于调 maxretry。
六、边界
- 数据来自单台实例:Ubuntu 22.04、ufw 0.36、fail2ban 0.11、华为云 ECS,观测窗口 2026-07-31 至 2026-11-04。样本量只有一台,不能推广成"所有云主机都这样"。
- "之后 9 天零记录"只能证明这台主机没收到,不能证明没人扫。安全组和上游链路丢掉的包,主机侧一个字节都看不到,想拿到那部分数据只能去云平台的流量日志里找。
- ufw 日志路径在 Debian/Ubuntu 系是
/var/log/ufw.log,RHEL 系用 firewalld,日志在 journal 里,zgrep那条命令不通用。 - 华为云安全组的默认规则、以及各区域对高危端口的处置策略会变,具体以控制台当前显示为准,本文不引用任何具体策略细节。
如果只能带走一句话:开服那 5 小时的密集探测是真的,但它会过去;真正决定这台机器安不安全的,是那 5 小时之后你有没有把门关小,而不是日志里那个吓人的数字。
- 点赞
- 收藏
- 关注作者
评论(0)