关闭 SSH 密码认证而不把自己关在门外
只用密钥是对暴露的 SSH 服务器所能做的最强单项改动。安全的操作顺序、真正起作用的配置行,以及它解决不了的问题。
为什么这是价值最高的改动
面向公网的 Linux 服务器几乎每一次失守,都始于一个有效密码——被猜中的、从别处泄露后复用的,或者被钓来的。关闭密码认证,这整一类就不再可能发生。不是更难:是不可能。根本没有密码可猜。
就投入产出而言,加固清单上没有别的条目能与之相比。它就是两行配置加一次重载。
人们迟迟不做,是怕做错,而这个风险是真实的:顺序错了,您就会把自己从一台只能通过 SSH 访问的机器上断开。本指南余下的部分就是这个顺序。
安全的操作序列
下面每一步都在进行下一步之前完成验证,而您所在的会话全程保持打开。不到最后不要关闭它。
首先,如果还没有密钥就生成一个。Ed25519 是当前的默认选择:更短、更快,强度至少不弱于 4096 位的 RSA。
# 1. 在您自己的机器上,而不是服务器上
ssh-keygen -t ed25519 -C "you@example.com"
# 2. 把公钥复制到服务器(最后一次询问您的密码)
ssh-copy-id user@server
# 3. 在「第二个」终端里验证,不要关闭第一个
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no user@server真正起作用的配置
只有在第 3 步成功之后,才去修改服务器配置。在现代发行版上,要改的文件未必是 sshd_config 本身:很多发行版带有 /etc/ssh/sshd_config.d/ 目录,其中的文件会被引入,并可能覆盖您在上面写的内容。
起作用的是四项设置:
# /etc/ssh/sshd_config.d/10-hardening.conf (或直接改 sshd_config)
PasswordAuthentication no
KbdInteractiveAuthentication no # 旧名称:ChallengeResponseAuthentication
PermitRootLogin prohibit-password # 若 root 从不直接登录,可设为 'no'
PubkeyAuthentication yes
# 重载前务必检查配置——这能抓住那些会导致 sshd 根本起不来的笔误:
sudo sshd -t
# 然后用 reload 而不是 restart:已有会话不会中断
sudo systemctl reload ssh # RHEL 系为 'sshd'确认改动已经生效
不要相信配置文件——去问 sshd 它实际解析成了什么。sshd -T 会打印经过所有引入与覆盖之后的有效配置:
sudo sshd -T | grep -iE 'passwordauthentication|kbdinteractiveauthentication|permitrootlogin'
# 期望输出:
# passwordauthentication no
# kbdinteractiveauthentication no
# permitrootlogin prohibit-password
# 再从外部验证:下面这条现在必须被拒绝
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password user@server它解决不了什么
只用密钥消除的是被猜中的风险。它既不消除流量,也不封堵所有入口。
机器人仍会继续连接。它们不知道您的配置,所以继续提交密码、继续被拒绝——每一次尝试依然消耗一个 TCP 连接、一次 sshd 分叉和一行日志。您的认证日志依然被噪音填满,您需要的那条事件依然会过期。仍然需要有东西来封禁来源。
另外,私钥是一个文件。它可能在被偷走的笔记本上、在某人误提交的仓库里、在 CI runner 的环境变量中。请用口令保护密钥、不要放在共享机器上,并在有人离职时轮换——泄露的密钥和泄露的密码一样糟糕。
它同样对未打补丁的 sshd、另一个端口上暴露的服务,或同一主机上的脆弱应用毫无作用。它是可用的最佳单项改动,同时也只是若干措施中的一项。
与之搭配的另一半
密码关掉之后,剩下的问题是量。SSH Protector 读取同一条认证流,封禁那些持续到达的来源——按子网、永久、开机恢复——并在封禁任何东西之前先把您自己的地址加入白名单。
它从 sshd 配置中识别真实的 SSH 端口,而不是想当然认为是 22,因此您已经迁移过的服务器无需任何配置即受保护。
只用密钥应对风险。封禁来源应对负载,并换来一份可读的日志,让您能注意到那唯一重要的事件。
FAQ
- 如何安全地关闭 SSH 密码认证?
- 先生成密钥,用 ssh-copy-id 复制上去,然后在第二个终端里验证仅用密钥可以登录,同时保持第一个会话开着。只有到这一步之后,才设置 PasswordAuthentication no 和 KbdInteractiveAuthentication no,运行 sshd -t 检查语法,并使用 reload 而非 restart。保持第一个会话打开,正是让错误可以补救的关键。
- 设了 PasswordAuthentication no,SSH 为什么还问密码?
- 几乎总是两个原因之一。要么 KbdInteractiveAuthentication 仍为 yes,PAM 通过另一条机制提供了密码提示;要么 /etc/ssh/sshd_config.d/ 里的某个文件在您的改动之后被引入并覆盖了它。运行 sudo sshd -T | grep -i passwordauth,看看 sshd 实际解析出的值。
- 该用 Ed25519 还是 RSA?
- 除非您的环境中有东西不支持,否则用 Ed25519。密钥短得多,验证更快,安全性至少等同于 4096 位 RSA。RSA 仍是老设备和旧客户端的有效备选;若使用它,请至少生成 4096 位。
- 只用密钥能阻止暴力破解尝试吗?
- 它让这些尝试永远不可能成功,这正是目的所在。但它不减少尝试次数:机器人无从得知您的配置,会无限期地继续连接并提交密码。您仍要为每次尝试付出连接、分叉和日志行的代价,因此封禁来源依然值得做。
