关闭 SSH 密码认证而不把自己关在门外

只用密钥是对暴露的 SSH 服务器所能做的最强单项改动。安全的操作顺序、真正起作用的配置行,以及它解决不了的问题。

阅读约 7 分钟

为什么这是价值最高的改动

面向公网的 Linux 服务器几乎每一次失守,都始于一个有效密码——被猜中的、从别处泄露后复用的,或者被钓来的。关闭密码认证,这整一类就不再可能发生。不是更难:是不可能。根本没有密码可猜。

就投入产出而言,加固清单上没有别的条目能与之相比。它就是两行配置加一次重载。

人们迟迟不做,是怕做错,而这个风险是真实的:顺序错了,您就会把自己从一台只能通过 SSH 访问的机器上断开。本指南余下的部分就是这个顺序。

安全的操作序列

下面每一步都在进行下一步之前完成验证,而您所在的会话全程保持打开。不到最后不要关闭它。

首先,如果还没有密钥就生成一个。Ed25519 是当前的默认选择:更短、更快,强度至少不弱于 4096 位的 RSA。

bash
# 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/ 目录,其中的文件会被引入,并可能覆盖您在上面写的内容。

起作用的是四项设置:

bash
# /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 会打印经过所有引入与覆盖之后的有效配置:

bash
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 位。
只用密钥能阻止暴力破解尝试吗?
它让这些尝试永远不可能成功,这正是目的所在。但它不减少尝试次数:机器人无从得知您的配置,会无限期地继续连接并提交密码。您仍要为每次尝试付出连接、分叉和日志行的代价,因此封禁来源依然值得做。

处理只用密钥之后剩下的流量

子网封禁、白名单优先、自动识别真实的 SSH 端口。一台服务器永久免费,无需信用卡。