结论: 防止暴力破解最有效的方式不是"把密码设复杂",而是让密码本身失去作用——改用 SSH 密钥登录并彻底禁用密码认证;在此基础上叠加 fail2ban 自动封禁、防火墙限速、端口收敛三层防护,把猜密码的成功概率降到趋近于零。
暴力破解(Brute Force Attack)是指攻击者用字典或穷举方式反复尝试用户名密码,直到撞对一个弱口令。它不需要任何技术含量,一台云主机放到公网上,几小时内 /var/log/secure 或 /var/log/auth.log 里就会堆满 Failed password for root from ... 的记录。更麻烦的是,这类扫描带来的不只是入侵风险:持续的连接尝试会消耗 SSH 的连接槽与 CPU,放任不管还可能让日志在几天内涨满磁盘。
为什么说"只靠复杂密码"挡不住暴力破解?
暴力破解的本质是把"一次猜对"变成"百万次里有一次对"。只要系统允许无限次尝试,任何密码在统计意义上最终都会被撞中。因此防御思路不是让密码更长,而是降低尝试次数上限——密钥登录让猜测无意义,fail2ban 让尝试次数封顶,防火墙让扫描者连握手都完不成。
下面这张表对比了几种常见防御手段的实际效果,建议按顺序自上而下叠加部署:
| 防御手段 | 位置 | 挡住什么 | 副作用 | 推荐度 |
|---|---|---|---|---|
| 强密码策略 | 应用层 | 弱口令字典 | 用户记不住,会写便签 | 基础,必做但不够 |
| SSH 密钥登录 + 禁用密码 | SSH 服务 | 99% 的密码爆破 | 私钥丢了就登不上 | 强烈推荐 |
| fail2ban 自动封禁 | 日志 + 防火墙 | 反复失败的来源 | 自己输错也会被封 | 强烈推荐 |
| 修改 SSH 端口 | SSH 服务 | 只扫 22 的低级扫描器 | 属于隐蔽而非安全,需同步改防火墙 | 可选 |
| firewalld/iptables 限速 | 网络层 | 高频连接洪水 | 极端时影响正常批量登录 | 推荐 |
| 仅允许白名单 IP 访问 | 网络层 | 一切非授权来源 | 出差/家里就登不上 | 有固定出口时推荐 |
| 单包授权 / VPN 接入 | 边界 | 端口完全不暴露 | 架构复杂度上升 | 高安全场景推荐 |
第一步:用 SSH 密钥登录替代密码认证
密钥登录是防爆破的第一道也是决定性的一道防线。它的原理是:服务端保存公钥,客户端持有私钥,登录时用数学运算证明你持有私钥,全程不传输任何可被猜测的秘密。
# —— 在【本地电脑】上生成密钥对(Windows 用 PowerShell / macOS Linux 用终端)——
ssh-keygen -t ed25519 -C "ops@company" -f ~/.ssh/company_ed25519
# 连按两次回车可跳过密码短语;生产私钥建议设置 passphrase
# 把公钥推送到服务器(会要求输入一次服务器密码)
ssh-copy-id -i ~/.ssh/company_ed25519.pub opsadmin@203.0.113.10密钥推送完成后,务必先新开一个终端窗口验证密钥可用,确认无误再关闭密码登录:
# —— 在【服务器】上修改 SSH 配置 ——
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
cat > /etc/ssh/sshd_config.d/99-no-password.conf <<'EOF'
PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM no
PubkeyAuthentication yes
PermitEmptyPasswords no
MaxAuthTries 3
EOF
# 校验语法,无输出即通过
sshd -t
systemctl restart sshd改完之后用一台新机器验证:ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no opsadmin@IP,应当立即被拒绝而不是提示输入密码。完整的 SSH 加固项见 服务器SSH安全怎么配置。
第二步:安装配置 fail2ban
fail2ban 的工作方式是"读日志 → 匹配失败规则 → 触发防火墙封禁"。它通过 jail(监狱)定义监控对象,通过 filter(过滤器)定义失败特征,通过 action(动作)定义封禁手段。
# Ubuntu 24.04
apt update && apt install -y fail2ban
# RHEL / Rocky / Alma 9 需先装 EPEL
# dnf install -y epel-release && dnf install -y fail2ban fail2ban-firewalld
systemctl enable --now fail2ban
fail2ban-client version不要直接修改 /etc/fail2ban/jail.conf,升级时会被覆盖。正确做法是新建 .local 文件:
cat > /etc/fail2ban/jail.local <<'EOF'
[DEFAULT]
# 白名单:把自己的固定出口 IP 和内网段加进来
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 203.0.113.5
# 封禁时长:600 秒;改为 -1 表示永久封禁
bantime = 600
# 统计窗口:10 分钟内
findtime = 600
# 失败几次触发封禁
maxretry = 5
# 递增封禁:重复违规者封禁时长逐级翻倍(1h → 12h → 1d → 8d ...)
bantime.increment = true
bantime.factor = 1
bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * 1.0
bantime.multipliers = 1 6 12 24 72 168
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log # Debian/Ubuntu
# logpath = /var/log/secure # RHEL/CentOS 系二选一
maxretry = 3
bantime = 3600
action = iptables[name=SSH, port=ssh, protocol=tcp]
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
EOF
systemctl restart fail2ban验证与运维常用命令:
# 查看所有启用的 jail 及当前被封 IP 数
fail2ban-client status
# 查看 sshd 监狱详情与封禁列表
fail2ban-client status sshd
# 手动解封误伤的 IP
fail2ban-client set sshd unbanip 198.51.100.23
# 手动永久拉黑某个 IP
fail2ban-client set sshd banip 198.51.100.23
# 直接看内核层面生效的 iptables 规则
iptables -L f2b-SSH -n -v --line-numbers除了 SSH,fail2ban 还内置了 nginx、Apache、Postfix、Dovecot、MySQL、WordPress(wordpress-hard.conf)等数十种过滤器,用于防御后台弱口令扫描同样有效。更完整的主机防护工具清单见 服务器安全软件推荐。
第三步:修改 SSH 端口到底有多大用?
改端口是争议最大的一条措施。结论是:它是"降噪"手段而不是"安全"手段,能挡住只扫 22 端口的批量脚本,但挡不住针对你的定向扫描——用 nmap -p- 全端口扫一遍就能找到新端口。
如果要改,请按以下流程走,避免把自己关在门外:
# 1. 先选一个未被占用的高位端口(1024~65535,避开常见服务)
ss -lntup | grep -w 23456 || echo "端口 23456 可用"
# 2. 防火墙先放行新端口,再改 SSH
ufw allow 23456/tcp comment 'ssh custom' # Ubuntu
# firewall-cmd --permanent --add-port=23456/tcp && firewall-cmd --reload # RHEL 系
# 3. 修改配置(注意 SELinux 环境需额外放行标签)
cat > /etc/ssh/sshd_config.d/10-port.conf <<'EOF'
Port 23456
EOF
# RHEL 系 SELinux 需执行:semanage port -a -t ssh_port_t -p tcp 23456
# 4. 校验并重启,然后用【新端口】开窗口验证,验证成功前不要关旧连接
sshd -t && systemctl restart sshd确认新端口可用后再关闭 22:先在云厂商安全组里移除 22 的放行规则,再在系统防火墙里删除,最后才把 sshd_config 里的 Port 22 注释掉。顺序反了容易踩坑。端口治理的整体思路见 服务器端口安全怎么设置。
第四步:网络层限速与白名单
这一层负责在连接建立前挡住洪水式尝试,常见做法是限制单位时间内的新建连接数。
# —— iptables recent 模块:60 秒内同一 IP 新建 SSH 连接超过 4 次则丢弃 ——
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSHSCAN
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update \
--seconds 60 --hitcount 4 --rttl --name SSHSCAN -j DROP
# —— firewalld rich rule 等价写法(RHEL 系推荐)——
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" service name="ssh" \
source ipset="trusted" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" service name="ssh" \
limit value="3/m" accept'
firewall-cmd --reload
# —— 最严格:只允许办公室固定出口 IP 访问 SSH ——
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.5/32" \
service name="ssh" accept'
firewall-cmd --reload对于 MySQL 3306、Redis 6379、MongoDB 27017 等永不应对公网开放的端口,正确做法是在云控制台安全组中直接不放行,并在系统里把服务绑定到内网网卡地址,而不是靠 fail2ban 兜底。
第五步:如何核验防爆破措施真的生效?
没有验证的防护等于没有防护。以下是三条可以立刻执行的核验手段。
# 1. 统计今日失败登录的来源 TOP 10
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head -10
# RHEL 系:grep "Failed password" /var/log/secure | ...
# 2. 统计已被 fail2ban 封禁过的 IP 总数
zgrep -h "Ban " /var/log/fail2ban.log* | wc -l
# 3. 观察实时防御日志
fail2ban-client -vvv start
tail -f /var/log/fail2ban.log一条健康的服务器,"失败登录"记录应该随时间明显下降——因为反复失败的 IP 已经被封掉了。如果一周后失败记录仍保持高位且来源分散,说明你遇到的是分布式爆破,此时应升级到云厂商的安全组限速或高防/云盾类产品,参见 服务器被攻击了怎么办 与 服务器怎么防DDoS攻击。
常见误区 / 排错提示
- fail2ban 装完就以为生效了。 Debian 系必须先确认
logpath指向/var/log/auth.log且backend = systemd;RHEL 系若仍用文件日志需改为/var/log/secure,否则 jail 里Currently failed: 0。 - Docker 环境下 fail2ban 封了 IP 但容器照样被访问。 Docker 会绕过 iptables 的 INPUT 链走 FORWARD 链,需要配合
-j DOCKER-USER链或使用下文 antipatterns 说明做调整。 - 自己连续输错密码被封,慌了就去改
maxretry = 100。 正确做法是把常用出口加进ignoreip,或者用fail2ban-client set sshd unbanip临时解封,而不是削弱策略。 - 改了端口但忘了改云厂商安全组,导致彻底失联。 云主机的安全组优先级高于系统防火墙,两者都要放通;先用控制台 VNC 登录再修。
- 把 fail2ban 的
bantime设为-1永久封禁后,日志被大量僵尸 IP 占满。 建议配合dbpurgeage保留期(默认 1 天到数年可调)与--restart定期清理,或使用 ipset + 定期落盘归档。
企业QQ咨询




