故事是这样的。
前阵子我买了个云服务器,火山引擎的,2 核 3.8G 内存 20G 磁盘,配置不高,但对我来说够用了,就干三件事,frp 中转隧道、Caddy 反向代理、DDNS 动态解析。
一开始我挺心大的,觉得就一个个人服务器,上面也没啥值钱的东西,安全差不多得了。
然后现实就给我上了一课。
某个周五晚上,我突然发现 SSH 连不上服务器了,22 端口直接超时,ping 能通,端口全封。
我第一反应是,卧槽,被黑了?
后来一查才发现,是火山引擎的面板把 22 端口给封了,原因是检测到暴力破解,触发了自动防护。
我当时的心情挺复杂的,一方面庆幸云厂商有自动防护,另一方面又很无语,我才部署了几天,就开始有人扫我端口爆破我的 SSH 了?
这台服务器公网 IP 暴露在互联网上,就像在闹市区开了个门,门没锁好,路过的每个人都想推一下试试。
也就是从那天起,我开始认真对待这台服务器的安全,前后折腾了一周,把能想到的加固措施全做了一遍。
先说 SSH 这块。
22 端口被封了,我就把 SSH 端口换到了 8222,然后去改 sshd_config,结果发现改了没用,端口还是老的。
排查了半天,最后发现是 Ubuntu 24.04 的 systemd 激活模式在搞鬼,ssh.socket 激活模式下,sshd 根本不读 sshd_config 里的 Port 指令,你得去 /etc/systemd/system/ssh.socket.d/ 里加一个 override.conf,写上 ListenStream 才行。
这个坑挺隐蔽的,网上资料少,我翻了好几个论坛才找到答案。
端口换完之后,我又把密码登录关了,只留密钥登录,root 也禁止直接登录,必须用普通用户 su 上去。
然后装了个 fail2ban,三次失败就封 IP 24 小时。
这套组合拳下来,我的 SSH 才算是真正安全了。
不过光搞 SSH 还不够,我服务器上跑了好几个 Web 服务,Caddy 反代了一堆子域名,这些入口也得防护。
Caddy 那边我挂了 forward_auth 统一鉴权,所有子域名都要过一道认证才能访问,认证失败五次就封一小时,用的是 fail2ban 的 caddy-auth jail。
后来我又加了一个 caddy-login jail,专门盯主站的登录接口,5 次失败封 1 小时,防止有人拿脚本暴力撞库。
这里有个细节我觉得值得说,fail2ban 的 jail 配置,网上大部分教程都是抄来抄去的,用的都是默认的 sshd jail,很少有人认真去配 Web 层的防护。但对我来说,SSH 反而不是最危险的,毕竟我有密钥,最危险的反而是那些暴露在公网的 Web 登录页,那才是被爆破的重灾区。
然后是最硬核的一步,iptables 端口隔离。
我服务器上有 14 条 frp 隧道,映射了各种内部服务的端口,2222、4042、5000、8118、1933、8080、8888、4041、5174、18789、8456、9119、5678、5001,这些端口在云服务器上都是对外开放的,外面的人可以直接连。
想想就后怕,这些端口后面全是我的内部服务,等于把家里的门全敞开了。
我的做法是,用 iptables 把所有 frp 隧道端口都限制成只允许 127.0.0.1 访问,外网直连直接 DROP。反正 frp 隧道本身是服务器主动连出去的,外网用户访问也是先到 Caddy,再被转发到本地,根本不需要直接连这些端口。
这条规则加上去之后,我整个人都踏实了,14 个端口从完全暴露变成了完全封闭,外面扫描器看到的只是一堵墙。
iptables 规则写完之后记得持久化,我用的是 iptables-persistent + netfilter-persistent,重启不丢。
还有两个小细节,一个是 frps 的 Dashboard,7500 端口,原来是直接绑在公网上的,管理界面裸奔,我把它改成了只绑定 127.0.0.1,要看的时候用 SSH 隧道看。另一个是 frp 的 token,原来是个很弱的默认值,我换成了一个强随机的 64 位十六进制字符串。
做完这些,我又把 frp 从 0.62.0 升级到了 0.70.1,顺手把 journald 日志限制在 500MB 七天轮转,避免日志把磁盘塞爆。
这套流程走完,我再去看服务器日志,心态完全不一样了。
以前看 auth.log 是心惊肉跳的,几百条爆破尝试记录刷屏,现在再看,干干净净,偶尔有几条 fail2ban 的封禁记录,那都是被自动挡下来的。
说真的,这次被暴力破解的经历,虽然有点吓人,但收获特别大。我以前总觉得安全是那些大公司才需要操心的事,我一个个人开发者,服务器上就那么几个服务,谁看得上啊。
事实证明我错了,在互联网上,没有谁是无足轻重的。你的服务器暴露在公网上,就会被扫描,就会被爆破,这不是针对你个人,而是全网自动化脚本的例行公事。
你被攻击,不是因为你重要,而是因为你是公网上的一个 IP。
这次之后我总结了几条经验,算是给自己立了个规矩。
第一,任何暴露公网的服务,先想清楚要不要暴露,能不暴露就不暴露,能走内网就走内网。像我的 frp 隧道端口,其实根本不需要对公网开放,直接 iptables 封死就完事了。
第二,登录入口必须有防护,SSH 换端口加密钥加 fail2ban,Web 登录页加 fail2ban 盯防,这是最低配置,不是可选配置。
第三,安全配置做完一定要验证,改完 sshd_config 要重启服务测一下,iptables 规则加完要扫一下端口确认真的封了,别改了等于没改。
第四,也是最重要的一条,永远假设你的服务器正在被攻击,然后基于这个假设去做防御。
其实我后来想想,这次被爆破还挺及时的,它在我服务器上还没放什么重要东西的时候就发生了,等于提前给我敲了个警钟。
如果再过几个月,等我上面跑满了业务再被爆破,那损失就不只是换个端口这么简单了。
现在我每次部署新服务,都会下意识地问自己三个问题,这个服务必须暴露公网吗,它的入口有防护吗,它的端口被 iptables 管住了吗。
三个问题都答是,我才敢把服务上线。
有时候我也会想,做技术的人是不是都有点被害妄想,总觉得全世界都在盯着自己的服务器。
但转念一想,这不是被害妄想,这是对互联网的真实认知。你的服务器在公网上的每一秒,都在被无数脚本扫描着,这不是比喻,是事实。
与其被动挨打,不如主动防御,把门锁好,把窗户关严,把报警器装上,然后该干嘛干嘛。
毕竟,在问为什么会被黑之前,先问问自己,我锁门了吗。
以上,既然看到这里了,如果觉得不错,随手点个赞、在看、转发三连吧,如果想第一时间收到推送,也可以给我个星标⭐~
谢谢你看我的文章,我们,下次再见。
本文作者:丘丘
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!