为什么 VPS 必须放弃纯密码登录
只要把一台有公网 IP 的 Linux 服务器开放 22 端口,用不了多久就会在日志里看到来自世界各地的暴力破解尝试。扫描器用常见用户名加字典密码的组合不断尝试,个人站长的服务器如果还用简单的 root 密码,被攻破只是时间问题。最有效的解决办法就是改用 SSH 密钥认证:密钥对由一长串随机字符组成,暴力穷举在计算上不可行,同时把密码登录彻底关掉,让扫描器连猜的机会都没有。本文以最流行的 OpenSSH 为例,从生成密钥对开始,完整走一遍密钥登录的部署和安全加固流程,并给出防止把自己锁在门外的应急方案。
第一步:生成密钥对,推荐 Ed25519 算法
密钥认证的原理是成对出现的密钥:私钥留在自己的电脑上,相当于钥匙,绝不能外传;公钥部署到服务器上,相当于锁。SSH 握手时服务器用公钥验证客户端是否持有对应的私钥,验证通过才允许登录。生成密钥对使用 ssh-keygen 命令,算法推荐 Ed25519,它比传统的 RSA 更安全、密钥更短、生成速度更快,主流发行版的 OpenSSH 都原生支持。
# 在本地电脑执行,不是服务器上
ssh-keygen -t ed25519 -a 100 -C "webmaster@example.com"命令执行后会出现两次询问,第一次问密钥保存路径,默认存在用户目录的 .ssh 文件夹下,直接回车即可;第二次问私钥口令,也就是 passphrase,建议设置一个。passphrase 的作用是给私钥文件再加一层密码保护,即使私钥文件泄露,攻击者没有口令也无法使用。担心麻烦的话,可以配合 ssh-agent 把密钥加载到内存里,之后一段时间内登录都不需要重复输入口令。生成完成后,本地会多出两个文件:id_ed25519 是私钥,权限必须是 600;id_ed25519.pub 是公钥,内容是一行以 ssh-ed25519 开头的字符串,可以随便给别人看。
第二步:把公钥部署到服务器
部署公钥最省事的方式是用 ssh-copy-id 命令,它会自动把公钥追加到服务器对应用户的 authorized_keys 文件里,并设置好正确的权限。命令会要求输入一次服务器密码,这是最后一次用密码登录。
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@你的服务器IP如果服务器上没有 ssh-copy-id 这个命令,也可以手动部署:先登录服务器,在用户主目录下执行 mkdir -p ~/.ssh 创建目录,然后编辑 authorized_keys 文件,把公钥内容粘贴进去,最后设置权限。权限非常关键:.ssh 目录必须是 700,authorized_keys 文件必须是 600,如果权限过宽,OpenSSH 出于安全考虑会直接忽略这个文件,导致密钥登录不生效。部署完成后,先不要关掉当前的 SSH 会话,另外开一个终端窗口测试密钥登录,确认能正常登录后再进行下一步,这是防止把自己锁在门外的第一道保险。
第三步:修改 sshd_config 关闭密码登录
密钥登录验证通过后,就可以修改 SSH 服务端配置了。配置文件位于 /etc/ssh/sshd_config,修改前先备份一份,然后逐项调整下面的参数。PermitRootLogin 建议改成 prohibit-password,意思是允许 root 用密钥登录但禁止用密码登录,既方便管理又堵住了 root 密码爆破这条路;如果你的服务器日常用普通用户登录、需要 root 时才 sudo,也可以直接设成 no。PasswordAuthentication 要改成 no,这是关闭密码登录的总开关。PermitEmptyPasswords 设 no,防止存在空密码账户时出现漏洞。
# /etc/ssh/sshd_config 关键配置
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 30MaxAuthTries 3 限制单次连接最多尝试三次认证,超过就断开,能有效减缓暴力破解的节奏;LoginGraceTime 30 限制登录握手必须在三十秒内完成,防止攻击者挂着一堆半开连接消耗资源。如果你的服务器只给自己和少数几个人用,还可以用 AllowUsers 白名单精确控制谁能登录,比如 AllowUsers webmaster,配置后其他用户名一律拒绝连接,比任何防爆破软件都干脆。修改完配置后,先执行 sshd -t 做语法检查,输出为空说明配置没有语法错误,然后执行 systemctl reload sshd 平滑重载。同样地,重载后先开新会话测试,确认密钥登录一切正常再断开旧会话。
第四步:安全重载的完整流程,防止锁死
SSH 配置改错导致无法登录,是新手站长最常踩的事故。这里给出一个万无一失的标准流程:第一步,在服务器上执行 sshd -t 验证语法,有错误会直接打印出来,先改到语法通过为止;第二步,执行 systemctl reload sshd 让配置生效,注意是 reload 不是 restart,reload 只重载配置不断连接;第三步,不要关闭当前终端,新开一个窗口用密钥登录测试,登录成功后这台服务器的加固才算完成;第四步,把当前这个旧会话正常退出。如果新会话登录失败,立刻在旧会话里把配置改回去,重新 reload 即可恢复。
万一所有的会话都断了,还有几条应急通道:云服务商的控制台一般都提供 VNC 或者网页终端,相当于坐在服务器屏幕前操作,这是最可靠的救援方式;有些服务商还提供救援模式,可以从外部挂载系统盘修改配置;实在不行,可以联系服务商的技术支持协助处理。为了避免这种惊险时刻,平时就应该养成习惯:任何涉及 SSH 配置的改动都先开一个新会话验证,再动旧会话。
第五步:多台服务器的密钥管理经验
手上服务器多起来之后,密钥管理就要讲究方法了。最简单的方式是一台电脑生成一对密钥,把同一个公钥部署到所有服务器上,私钥只存在本地电脑,管理成本最低,代价是一旦私钥泄露,所有服务器都暴露,所以私钥的 passphrase 一定要设置。进阶一点的做法是给不同用途的服务器生成不同的密钥对,用 SSH 配置文件按主机区分,在本地用户目录的 .ssh/config 里为每台服务器指定对应的密钥文件,登录时 ssh 会自动匹配,命令可以简写成 ssh 主机别名。配置示例:Host myserver 下面写 HostName 服务器IP、User root、IdentityFile ~/.ssh/myserver_ed25519 三行,之后直接 ssh myserver 就能登录。
关于私钥安全还有几条铁律:私钥文件不要同步到网盘、不要发到聊天工具里、不要提交到代码仓库,这些地方一旦泄露就是灾难;换电脑或者重装系统前,先把私钥和 passphrase 妥善备份到离线介质;如果怀疑私钥泄露,立即在服务器上从 authorized_keys 里删掉对应的公钥,再重新生成一对新的。authorized_keys 文件支持一行一个公钥,管理多台电脑的访问就是把各自的公钥各占一行加进去,要撤销某个人的访问权限,删掉他那行即可,比改密码更精准。
第六步:配合其它手段,形成纵深防御
关闭密码登录之后,暴力破解基本被挡在门外,但纵深防御仍然值得做。防火墙层面,用 iptables 或者云服务商的安全组把 22 端口限定在你的常用 IP 段,家里宽带是动态 IP 的就限定到运营商分配的地址段,能挡住绝大多数扫描。fail2ban 可以监控 SSH 日志,把多次认证失败的 IP 自动加入封禁名单,即使还有别的认证途径暴露,也能自动处置攻击源。再进一步,可以修改 SSH 监听端口,把 22 换成高位端口,虽然不能提供真正的安全,但能大幅减少扫描噪音,让日志清净不少。有条件的话还可以开启双因素认证,用手机上的验证器生成动态码,登录时除了密钥还要输入验证码,安全性直接上一个台阶。这些手段按需组合,不必全部上,个人服务器做到密钥登录加防火墙限源,已经超过绝大多数站长的安全水平了。
小结
SSH 密钥登录加固的完整流程可以概括为六步:生成 Ed25519 密钥对、用 ssh-copy-id 部署公钥、修改 sshd_config 关闭密码登录、按标准流程安全重载、做好多服务器密钥管理、配合防火墙和 fail2ban 形成纵深防御。整个过程中最核心的纪律是:任何一步改动都要先验证再断线,密钥文件永远只留在自己的设备上。这套配置一次做好,长期受益,从此服务器日志里那些来自全球的破解尝试就再也构不成威胁,你也能睡得安稳一些。