你的服务器正被黑客扫密码?如何设置更安全的SSH 密钥登录
-
-
2026 年 7 月 28 日 上午 12:09 #34384
你买了一台 Ubuntu 服务器,或者在自己的旧电脑上装了 Ubuntu Server 当家庭服务器用。你每次登录都在终端里敲:
ssh user@你的IP然后老老实实输密码。
这个场景你大概不陌生。但你很可能不知道的是——在你敲下回车的那一刻,全世界有无数台机器正在对你的服务器做同样的事。只不过它们是在自动跑脚本,每秒尝试几十上百个常见的用户名和密码组合。
如果你不信,现在就登录你的服务器看一下:
sudo journalctl -u sshd | grep "Failed password" | tail -20或者(经典路径):
sudo cat /var/log/auth.log | grep "Failed password" | tail -20你十有八九会看到一堆登录失败的记录,来自各种你听都没听过的 IP 地址。这不是你的服务器”被盯上了”——这就是互联网的常态。任何一台暴露在公网上的 SSH 服务器,从上线第一秒就在被暴力破解脚本扫描。
那怎么办?禁用密码登录,改用 SSH 密钥认证。
一、为什么密码认证从根上就是错的
密码认证有三个无法修补的结构性缺陷:
1. 密码可以被暴力破解
暴力破解不需要多高深的技术。一个简单的脚本用常见密码字典(”admin”、”123456″、”password”、”root” 等),每秒试几十个组合,配合多线程、IP 轮换,24 小时内能试几百万次。只要你的密码不够复杂——坦白说,大多数人的密码都不够复杂——终归会被试出来。
2. 密码在传输时可能被暴露
很多人以为 SSH 连接是加密的。是的,连接建立之后的数据传输确实加密了。但问题在于:密码是在连接建立过程中传输的。如果有人在你和服务器之间做了中间人攻击(MITM),你的密码可能在传输过程中被截获。
3. 密码是”共享秘密”——你知道,服务器也知道,甚至别人也知道
密码的本质是一个”你知我知”的共享秘密。凡是共享的秘密,就有泄露的风险:
- 你可能在不同服务器上用了相同的密码,一台失守全部沦陷
- 你可能把密码告诉了同事、家人,或者记在某个云笔记里
- 服务器的
/etc/shadow文件虽然存的是哈希,但如果哈希算法不够强(比如旧的 DES),可以被离线彩虹表破解
三个问题加在一起,结论很清晰:用密码做 SSH 认证,不是”不够好”,而是”迟早出事”。
二、SSH 密钥认证是如何工作的?用一把锁就能讲明白
想象你有一套这样的东西:
- 一把打开的锁——锁是开着的状态,任何人都能看、能摸、能挂到任何地方。它本身锁不住任何东西,但可以用来验证。
- 一把匹配的钥匙——能把这把锁锁上,也能把它打开。
SSH 密钥认证的原理,和这套”锁-钥匙”机制几乎对应:
- 公钥(public key,
.pub文件) = 那把打开的锁。你可以大大方方地把它放在服务器上、发给别人、贴到墙上——它本身不提供任何准入权限。 - 私钥(private key,没有后缀的文件) = 那把唯一的钥匙。必须藏好,谁也不给。 谁拿到它,谁就能以你的身份登录任何放了对应公钥的服务器。
整个登录过程是这样走的:
你(持有私钥) 服务器(存有你的公钥) │ │ │───────── 1. "我是 user,我要登录" ──────→│ │ │ │←──── 2. "证明一下,请签名这段随机数据" ───│ │ │ │── 3. 用私钥签名,发回签名结果 ──────────→│ │ │ │ 4. 用公钥验证签名 ✓ │ │←─────────────────── 登录成功 ───────────│关键点在于第 3 步:私钥只在你自己的电脑上被调用,它从未离开过你的机器。 发出去的只是一段签名结果。
你给了服务器一个”零知识证明”式的回答:我证明了”我拥有私钥”这件事,而不需要把私钥本身交出去。
相比密码认证,做一次完整的对比:
维度 密码认证 密钥认证 凭证谁保存 你知道,服务器也存了(哈希) 只有你持有私钥 传输过程 密码明文或哈希值在网络中传递 私钥不出本地,只发签名 暴力破解 在线脚本每秒试几百次 数学上不可能暴力破解私钥 中间人攻击 可能被截获密码 签名无法反推私钥 钓鱼攻击 假服务器可以骗取密码 假服务器无法骗取私钥签名 日常使用 每次都要输入,麻烦 一次设置,之后免密 多服务器管理 记住 N 组不同密码(或重复使用) 一个私钥对 N 台服务器 撤销权限 改密码(影响所有知道新密码的人) 从 authorized_keys 删一条公钥即可 三、实操:从零到一,彻底禁用密码登录
以下操作分为四步,每一步有明确的验证点。强烈建议按顺序执行,不要跳过验证步骤。
第一步:在你的本地机器生成密钥对
打开你的本地终端(不是服务器的终端——是你自己电脑的终端)。
ssh-keygen -t ed25519 -C "你的邮箱@example.com"参数说明:
-t ed25519:指定密钥类型为 Ed25519。比传统的 RSA 更快(生成和签名都在毫秒级)、更安全(同等安全强度下密钥更短),是目前 SSH 密钥的推荐选择。-C "你的邮箱":一条注释,方便你日后管理多个密钥时区分。
执行后你会看到类似这样的交互:
Generating public/private ed25519 key pair. Enter file in which to save the key (/Users/你/.ssh/id_ed25519):直接按回车接受默认路径即可。
然后会问你要不要设置 passphrase(稍后解释):
Enter passphrase (empty for no passphrase): Enter same passphrase again:对于这一步,你可以选择先留空,等全部配置完成后,再回过头来给私钥加一道锁。我们会在后面的”进阶加固”一节专门讲这个。
生成完成后,你会得到两个文件:
~/.ssh/id_ed25519——私钥,绝不给任何人看~/.ssh/id_ed25519.pub——公钥,需要放到服务器上
第二步:把公钥传送到服务器
你有三种方式可以实现这一步。任选其一。
方式 A(推荐,最简单):使用 ssh-copy-id
ssh-copy-id user@你的服务器IP它会自动把你的公钥追加到服务器
~/.ssh/authorized_keys文件中。方式 B(手动操作,适合需要精细控制的情况):
在本地查看公钥内容:
cat ~/.ssh/id_ed25519.pub复制输出的全部内容,然后 SSH 登录服务器:
ssh user@你的服务器IP在服务器上执行:
mkdir -p ~/.ssh chmod 700 ~/.ssh echo "粘贴你复制的公钥内容" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys exit方式 C(带外注入):
如果你是云服务器(AWS、阿里云、腾讯云等),绝大多数厂商在创建实例时允许你直接粘贴公钥。这种情况下你第一次 SSH 登录就已经是密钥认证了,不需要密码。
⚠️ 不管你用哪种方式,这一步都要输入一次密码。 因为服务器上还没有你的公钥,只能用密码让你进去。这是你最后一次输入密码——忍一下。
第三步:验证密钥登录(最重要的一步)
保持当前 SSH 会话不要断开。 打开一个新终端窗口,测试:
ssh user@你的服务器IP如果一切正常,你应该直接登录成功,不需要输入任何密码。这证明密钥认证已经生效。
如果登录失败,请检查:
- 本地私钥路径是否正确:
ls -la ~/.ssh/ - 服务器上公钥是否写入正确:登录服务器后执行
cat ~/.ssh/authorized_keys - 权限是否正确(常见错误):
~/.ssh必须是700,authorized_keys必须是600
在确认密钥登录可用之前,千万不要关闭你原有的 SSH 会话。 这是最后一道安全网——如果密钥登录有问题,你还可以通过旧会话排错。一旦你两边都断了,而密钥又不好使,你就会被锁在门外。
第四步:禁用密码登录(最后一刀)
密钥确认能用之后,接下来就是把密码认证彻底关掉。
在服务器上编辑 SSH 配置文件:
sudo vim /etc/ssh/sshd_config如果没有
vim,用sudo nano /etc/ssh/sshd_config也一样。找到并修改(或新增)以下三行:
PasswordAuthentication no PubkeyAuthentication yes ChallengeResponseAuthentication no保存退出,然后重启 SSH 服务:
sudo systemctl restart sshd现在再试一次新开终端的 SSH 连接。 你应该只能通过密钥登录,密码方式已经彻底失效。
如果你对 vim 不熟悉,这里有个偷懒的方法:用 sed 直接改。
# 备份原配置(建议养成习惯) sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak # 修改配置 sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config sudo sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config sudo sed -i 's/^#\?ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config # 重启服务 sudo systemctl restart sshd四、”服务器会接受任意密钥吗?”
这个问题非常好,也是很多初次接触密钥认证的人最大的困惑。
答案很明确:不,服务器只接受你明确授权过的公钥。
当你禁用密码登录后,服务器只认
~/.ssh/authorized_keys这个文件里的公钥。这个文件里有什么公钥,才允许什么人登录——一条不多,一条不少。 不是你拿着任意一把私钥就能登的。而且这个文件的修改权限是受限的:
- 只有文件所有者(也就是你登录的那个用户)和 root 才能写它
- 文件权限应该是
600(只有所有者可读写) - 父目录
~/.ssh权限应该是700(只有所有者可读可写可执行)
所以完整的安全链条是这样的:
你有服务器的账号密码 → 你才能 SSH 进去 → 才能修改 authorized_keys → 才能添加你的公钥 → 才能用密钥登录或者(从攻击者的视角):
攻击者没有你的私钥 → 无法签名 → 无法通过密钥认证 → 拒绝登录 (密码认证已禁用,暴力破解通道彻底关闭)根本不存在”任意密钥都能登”的情况。 你往
authorized_keys里写谁的公钥,谁才能登。你写你自己的,就只有你能登。你要撤销某个人的访问权限,从他对应的服务器上删掉他那一行公钥就行了——不用改密码、不用通知其他人、不影响其他有效密钥。至于私钥本身的安全性:Ed25519 密钥是 256 位随机数。暴力破解一个 256 位私钥需要的计算量,用目前全人类所有计算机加在一起算到宇宙热寂也解不出来。这个”安全”不是”比较安全”或”一般安全”,而是数学上可行性的边界之外的安全。
五、进阶加固:让你的密钥更安全
5.1 给私钥加一道口令(passphrase)
回想第一步生成密钥时被问到的那个”passphrase”——它不是用来登录服务器的,而是用来加密你本地的私钥文件的。
没有 passphrase:私钥文件以明文存放在
~/.ssh/id_ed25519里。谁拿到这个文件,谁就能直接用它登录你的服务器。有 passphrase:私钥文件是加密存储的。别人即使拿到了你的私钥文件,没有口令也无法使用。私钥的泄漏就不再是灾难级别的——攻击者还得多过一道关。
如果你生成密钥时没设 passphrase,现在可以补上:
ssh-keygen -p -f ~/.ssh/id_ed25519它会提示你输入旧的口令(留空表示没有)和新口令。
设置之后,每次使用这个私钥(SSH 登录、Git 推送等)都需要输入一次口令。如果你觉得麻烦,可以用
ssh-agent把解密的私钥暂存在内存中:eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519输入一次 passphrase 后,整个终端会话期间,再次使用这个私钥的时候不会再问你要口令。关机或退出终端后,缓存自动清除。
5.2 管理多个密钥对
你可以针对不同的用途生成不同的密钥对:
# 一台密钥用于个人服务器 ssh-keygen -t ed25519 -C "personal" -f ~/.ssh/id_ed25519_personal # 另一台用于工作服务器 ssh-keygen -t ed25519 -C "work" -f ~/.ssh/id_ed25519_work然后在
~/.ssh/config中配置每个主机使用哪个密钥:Host personal-server HostName 192.168.1.100 User kola IdentityFile ~/.ssh/id_ed25519_personal Host work-server HostName work.example.com User kola IdentityFile ~/.ssh/id_ed25519_work这样,
ssh personal-server和ssh work-server会自动使用对应的密钥。5.3 定期轮换密钥
虽然私钥泄露概率极低,但良好的安全习惯是定期更换。建议——不需要太频繁,一年一次足够了:
- 生成新密钥对
- 把新公钥上传到服务器(追加到
authorized_keys,保留旧公钥作为后备) - 验证新密钥能登录
- 删除旧公钥
六、万一出了事怎么办
场景一:我把自己锁在外面了
这是 SSH 密钥迁移过程中最常见的事故。如果你禁用了密码登录但密钥认证又没配置好,你就被拒之门外了。
救援方案(取决于你的环境):
- 云服务器:几乎所有云厂商都提供 VNC 控制台或”救援模式”,可以从网页端直接登录服务器的终端(不需要 SSH)。登录进去之后修正配置。
- 本地服务器/树莓派:接上显示器和键盘,物理登录。
- 家庭服务器(无显示器):重启服务器,在引导过程中进入单用户模式,或者从 U 盘启动 Live 系统挂载硬盘修改。
修改
/etc/ssh/sshd_config,临时把PasswordAuthentication no改回yes,重新检查密钥配置,认证通了之后再次关掉。场景二:我的私钥丢了
私钥丢了 = 你再也登不上服务器。没有找回途径,没有密码重置功能,没有客服电话。
这不是 Bug,这是设计。 如果私钥可以”找回”,那别人也能找。
预防方案只有一个:备份。
# 用加密压缩备份私钥 tar czf ssh-keys-backup.tar.gz ~/.ssh/ gpg -c ssh-keys-backup.tar.gz # 加密然后把加密后的文件存到:
- 密码管理器(1Password、Bitwarden 等)
- 离线的 U 盘(物理隔离)
- 打印成二维码存到保险柜(如果你真的很 paranoid)
场景三:私钥被泄露了
- 立即从所有服务器的
authorized_keys中删除对应的公钥行 - 生成一对新密钥
- 分析泄露路径,确保同样的错误不会发生第二次
- 永远不要把你的私钥发给任何人,永远不要粘贴到网页里,永远不要上传到 GitHub
七、补充:一些扫尾操作
如果你有多个用户
每个用户各自在自己的目录下执行同样的流程(
~/.ssh/authorized_keys是每个用户独立的)。Root 登录建议直接用
sudo而不是直接 SSH 登录,做法是禁用 root 的 SSH 登录:PermitRootLogin no日常用一个普通用户登录,需要提权时用
sudo。如果你改了 SSH 端口
如果你把默认的 22 端口改了(建议改,能减少 99% 的暴力扫描日志),在连接时加上
-p参数:ssh -p 端口号 user@服务器IP或者在
~/.ssh/config中配置:Host my-server HostName 你的IP Port 端口号 User user验证配置是否生效
你可以用 SSH 的调试模式验证密码登录是否确实被禁用:
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no user@服务器IP如果配置正确,这条命令应该返回
Permission denied (publickey)——服务器拒绝了密码认证,只接受密钥。这正是你想要的效果。八、常见问题速查
问题 回答 密钥登录安全吗? 安全。私钥 256 位随机数,数学上不可暴力破解。 服务器会接受谁的密钥? 只接受 ~/.ssh/authorized_keys里列出的公钥。Mac/Linux 怎么操作? 本文步骤适用于所有类 Unix 系统(macOS、Linux、WSL)。 Windows 怎么操作? 推荐用 PowerShell 或 Terminal,也支持 OpenSSH 客户端。 设置需要多久? 10 分钟。 以后还能再加别人吗? 可以,把新人的公钥追加到 authorized_keys即可。私钥能不能用 U 盘带着走? 可以,但不推荐。私钥应该留在你自己信任的设备上。 passphrase 忘了怎么办? 私钥作废,重新生成一对。 多个设备登录同一台服务器? 每个设备生成自己的密钥对,各自的公钥都加到服务器 authorized_keys。重装系统后怎么登录? 如果你备份了私钥,把备份的私钥恢复回来即可。如果没备份,通过带外方式重新加公钥。 九、所以说到底
前面讲了很多原理和步骤,但对小白来说,核心记住三句话就够了:
- 密码认证不安全——你的服务器每天都在被暴力扫描,迟早被攻破。
- 密钥认证从根本上解决了这个问题——私钥不出本地,数学上不可破解,服务器只认你授权过的公钥。
- 设置很简单——三步:生成密钥 → 推送公钥 → 关闭密码。10 分钟,一劳永逸。
花 10 分钟做完这件事之后,你可以把”SSH 安全”这个担忧彻底从脑子里删除——暴力破解不再关你的事,中间人攻击不再关你的事,密码泄露不再关你的事。
你的服务器会感谢你的。确切地说,是未来的你自己会感谢现在的你。
-
- 抱歉,回覆主題必需先登入。