暴露在公网的Ubuntu服务器,从上线那一刻起就开始被各种自动化扫描器轮番探测。这些扫描流量并非都是无害的,很多是攻击者寻找弱口令、已知漏洞和配置缺陷的前奏。放任不管,轻则日志被刷爆、带宽被浪费,重则被攻破植入后门。下面直接进入具体的配置环节,用一套组合拳把恶意扫描的噪音降到最低,并让真正的攻击难以得手。
更换默认SSH端口,但别只依赖它默认的22端口是扫描器重点关照对象。修改端口能立即过滤掉90%以上的自动化扫描。编辑SSH配置文件:
sudo nano /etc/ssh/sshd_config
找到 #Port 22 这一行,去掉注释并将数字改成一个高位端口,比如 Port 22960。注意别用2222这类常见替代端口,扫描器也会尝试。保存后重启服务 sudo systemctl restart sshd。新开一个终端测试新端口能正常登录,确认无误后再关闭原来的22端口会话,避免把自己锁在服务器外面。这只是障眼法,绝不能作为唯一的安全措施,必须结合下面的手段。
Fail2ban通过监控日志,在短时间内检测到多次失败尝试后,自动在防火墙层面封锁来源IP一段时间。安装很简单:
sudo apt update && sudo apt install fail2ban -y
不要直接修改主配置文件,而是创建一个本地覆盖文件:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
编辑 jail.local,重点配置以下几个参数。在 [DEFAULT] 段中,设置白名单IP,把你自己的固定IP或跳板机IP加进去,防止误封:
ignoreip = 127.0.0.1/8 ::1 你的IP地址 bantime = 3600 findtime = 600 maxretry = 3
这里的意思是,在600秒内失败3次,就封禁该IP一小时。接着针对SSH服务,找到 [sshd] 段落,确保它处于启用状态并指定你修改后的端口:
[sshd] enabled = true port = 22960 logpath = /var/log/auth.log backend = %(sshd_backend)s
重启Fail2ban使其生效:sudo systemctl restart fail2ban。用 sudo fail2ban-client status sshd 就能看到当前SSH监狱的封禁统计。攻击者的IP会被动态加入iptables规则中,时效过后自动解封。
Ubuntu自带的UFW是iptables的友好前端。原则是默认拒绝所有入站连接,只开放必须的服务端口。
sudo ufw default deny incoming sudo ufw default allow outgoing
然后精确放行你需要的端口。假设你有一个Web服务,并且SSH端口改成了22960:
sudo ufw allow 22960/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp
如果你只允许特定IP访问SSH端口,可以进一步限制来源地址,这比单纯改端口安全得多:
sudo ufw allow from 你的IP地址 to any port 22960 proto tcp
最后启用防火墙:
sudo ufw enable
用 sudo ufw status numbered 检查规则列表,确保没有多余的开放端口。数据库端口如3306、6379等绝对不要对公网开放,如果有需要,用内网通信或SSH隧道。
密码认证是暴力破解的根源。只要条件允许,应该彻底关闭密码登录,只使用密钥对认证。在你本地电脑生成密钥对(如果还没有的话):
ssh-keygen -t ed25519 -C "你的注释"
将公钥复制到服务器:
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 22960 用户名@服务器IP
测试密钥登录成功后,再次编辑 /etc/ssh/sshd_config,进行以下硬核修改:
PasswordAuthentication no ChallengeResponseAuthentication no UsePAM no PermitRootLogin no
PermitRootLogin no 禁止root直接远程登录,必须先用普通用户登录再 sudo -i 提权,这增加了攻击者获取root权限的难度。如果必须保留密码登录(例如某些自动化部署场景),那么至少要用 AllowUsers 指令明确限定哪些用户可以登录,并确保这些用户的密码强度足够高。
对于高度敏感的SSH端口,Port Knocking是一种高级隐蔽手段。它要求客户端先按特定顺序“敲击”一组预设的端口,服务器检测到这个序列后,才临时将该客户端的IP加入防火墙白名单,开放SSH端口。安装 knockd:
sudo apt install knockd -y
编辑 /etc/knockd.conf,配置一个敲门序列。例如,你需要依次访问 7000, 8000, 9000 这三个端口来打开SSH,访问 9000, 8000, 7000 来关闭它:
[options] UseSyslog [openSSH] sequence = 7000,8000,9000 seq_timeout = 5 command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22960 -j ACCEPT tcpflags = syn [closeSSH] sequence = 9000,8000,7000 seq_timeout = 5 command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22960 -j ACCEPT tcpflags = syn
接着编辑 /etc/default/knockd,将 START_KNOCKD=0 改为 1,并指定监听的网卡,例如 KNOCKD_OPTS="-i eth0"。启动服务后,你的SSH端口在扫描器眼中就是关闭状态,只有知道敲门序列的人才能让它现身。这需要确保你的UFW规则里没有直接开放22960端口,而是由knockd动态管理。
扫描器常用ICMP回显请求来探测主机是否存活。虽然完全禁Ping可能影响一些网络诊断,但对于高安全需求场景,可以考虑限制。更重要的是一些内核层面的网络参数调优,可以增强抵御SYN洪水扫描和IP欺骗的能力。编辑 /etc/sysctl.conf 或创建 /etc/sysctl.d/99-security.conf 文件,加入以下参数:
# 忽略ICMP广播请求 net.ipv4.icmp_echo_ignore_broadcasts = 1 # 忽略所有ICMP回显请求(根据需求开启,默认建议关闭) # net.ipv4.icmp_echo_ignore_all = 1 # 启用SYN Cookie保护,防止SYN洪水攻击 net.ipv4.tcp_syncookies = 1 # 记录并丢弃欺骗包、源路由包、重定向包 net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.default.log_martians = 1 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.all.send_redirects = 0 # 增加TCP连接积压队列大小 net.core.somaxconn = 1024 net.ipv4.tcp_max_syn_backlog = 2048
保存后执行 sudo sysctl -p 让配置立即生效。这些参数让服务器的网络协议栈更健壮,能默默丢弃大量畸形探测包,而不消耗过多资源。
防火墙和Fail2ban处理的是网络层面的恶意行为,但万一有攻击者突破了防线,你需要第一时间知道系统关键文件是否被篡改。AIDE(Advanced Intrusion Detection Environment)是一款主机入侵检测工具,它能对所有监控的文件生成校验和数据库,一旦文件被修改、删除或新增,就能在下次检查时发现。
sudo apt install aide -y
初始化数据库:
sudo aideinit
这个过程会扫描整个系统,比较慢。完成后,初始数据库会被创建。将生成的数据库文件重命名为正式库:
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
之后,定期运行检查命令来比对变化:
sudo aide.wrapper --check
可以设置cron定时任务,每天凌晨执行一次检查并将结果发邮件给你。任何对 /bin、/sbin、/etc 等关键目录的未授权修改都将暴露无遗。
扫描器识别目标后,会进一步探测Web服务器、数据库等服务的版本信息,寻找已知漏洞。你应该主动隐藏这些信息。对于Nginx,在 nginx.conf 的 http 块里设置:
server_tokens off;
对于Apache,在配置文件中设置:
ServerTokens Prod ServerSignature Off
如果运行着SSH,即使改了端口,版本号也可能暴露。在 sshd_config 中,可以设置一个伪装字符串(虽然这不是真正的安全措施,但能增加噪音干扰):
VersionAddendum "none"
更彻底的做法是使用自定义编译或反向代理来完全重写或删除这些响应头。对于数据库等不应暴露的服务,确保它们只监听 127.0.0.1 而不是 0.0.0.0,这能从根源上杜绝被外部扫描到。
所有的配置都不是一劳永逸的。你需要知道你的服务器正在经历什么。除了Fail2ban的日志,应该集中关注 /var/log/auth.log 中的认证失败记录。可以手动用命令分析高频攻击IP:
sudo grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head
对于更复杂的场景,部署一个轻量级的日志管理工具,比如Loki+Promtail+Grafana,或者ELK Stack的简化版,来可视化呈现恶意扫描的来源地图、攻击频率和攻击类型。设置阈值告警,当某类事件在短时间内爆发式增长时,能通过邮件或即时通讯工具收到通知,这样你就能及时调整防御策略,比如手动封禁一个IP段。
这一整套配置下来,你的Ubuntu服务器就从一台在公网上裸奔的机器,变成了一个沉默、坚固且警觉的堡垒。自动化扫描器会发现大部分端口都不可达,SSH服务仿佛不存在,偶尔的暴力尝试会立刻被关进小黑屋,而任何深入系统的篡改行为都会触发警报。安全不是一次性的设置,而是持续的对抗过程,保持系统和软件的更新,定期审计配置,才是长久之道。
