资讯动态

SSH密钥认证完全指南:从密码登录切换到非对称加密的实战细节

发布时间:2026/10/17 1:16:57 来源:尧图企业网站定制
最近在给实验室的一批服务器统一配置远程登录方式一开始所有人都是用密码登录结果问题层出不穷有人把密码设成了123456有人把密码随手写在便签上贴在显示器边框还有人离职交接的时候压根忘了改密码。痛定思痛我干脆把整个环境都切换到SSH密钥认证顺便把整个过程的细节整理成了一份学习小结。这篇内容适合刚接触Linux服务器的初学者也适合那些一直在用密码登录但想切换成密钥认证的运维同学我会把实际操作中遇到的坑和排查思路一起写出来。1. 远程联机这件事为什么要从密码认证切换到密钥认证1.1 密码认证的问题到底出在哪里很多刚接触服务器的人觉得SSH远程登录就是输入用户名和密码连上去完事。这个认知不能说错但在真实的生产环境里密码认证的短板非常明显。首先是密码本身的安全强度问题。弱密码被暴力破解几乎是时间问题哪怕你把密码设成长度很长、大小写加特殊字符的组合只要它是静态的、写在某个地方的东西就有泄漏的可能。我们实验室之前就发生过一次比较尴尬的事某台测试服务器的root密码被一位同学写在了项目文档的共享目录里结果整份文档被人拖走服务器也被人登录过。虽然那台机器上没什么重要数据但排查过程非常折腾。其次是密码认证在多人协作场景下的管理难题。每个人都需要记住一个密码密码一旦需要轮换就得通知所有人修改总有人忘了改总有人把新密码发到聊天群里。这种情况下密码实际上已经成了一个共享的秘密而不是个人的凭证。1.2 密钥认证的底层逻辑你拥有什么比你知道什么更可靠密钥认证的核心思想是非对称加密。简单的类比是这样你有一把私钥和一把公钥公钥可以随便发给别人私钥必须自己保管。当你登录服务器的时候服务器会用它保存的公钥向你发起一个挑战只有持有对应私钥的客户端才能正确应答。整个过程不需要在网络上传送私钥私钥永远只存在于你的本地机器上。这就解决了密码认证的核心痛点不需要你记住任何字符串不需要在一个共享环境里传递秘密服务器只认你手里有那把私钥这个事实。但也正因为只认私钥私钥的保管就变得至关重要。如果你把私钥拷来拷去、放在U盘里弄丢了、或者干脆放在共享目录里那密钥认证的安全性和密码认证没什么区别甚至更糟。所以我在切换密钥认证的同时给每个人都明确了几条规矩私钥不离开个人电脑、私钥必须设置额外的口令保护、公钥才允许分发。1.3 什么场景下适合直接切换密钥认证密钥认证并不适合所有场景。如果是一台只有你自己用的个人开发机密码认证偶尔用一下其实没什么问题但如果是多人共用的服务器、对外开放的服务节点、或者承载了业务数据的机器那就很有必要强制切换到密钥认证。我个人的建议是先在测试环境把流程跑通确认密钥认证能正常登录之后再关掉密码登录。不要一上来就把PasswordAuthentication no写进配置文件否则一旦密钥配置有问题你就会被锁在门外。这个教训我栽过跟头后面会详细说。2. 密钥对生成选型、命名与私钥保管的第一课2.1 用ed25519还是RSA这是个值得想清楚的问题SSH密钥对生成最常用的命令是ssh-keygen但在选择密钥类型上很多人都是直接用默认选项也就是RSA。RSA本身没问题但如果你手头的OpenSSH版本支持Ed25519我会更推荐用这个算法。原因在于Ed25519的密钥长度更短生成和验证的速度更快安全性在现代密码学标准下也足够可靠。我在给实验室的一批新服务器生成密钥时全部采用的ed25519命令是ssh-keygen -t ed25519 -a 100 -C lab-server-2025这里的-a 100表示对私钥文件做100轮KDF密钥派生函数迭代用来抵御离线暴力破解。-C后面是注释建议写上用途或机器名方便以后维护时快速辨识这把密钥是谁的、是干嘛用的。RSA也有它的场景某些老旧的系统和硬件设备只支持RSA比如一些网络设备或者很老版本的服务器系统那就只能生成RSA密钥。生成RSA密钥时建议指定长度至少为4096命令是ssh-keygen -t rsa -b 4096 -C comment2.2 密钥文件的位置、命名与权限管理生成完后默认会在~/.ssh目录下生成两个文件id_ed25519是私钥id_ed25519.pub是公钥。私钥文件的权限必须是600只有所有者可读写公钥文件的权限可以是644所有人可读也没有问题但实际上我会把整个.ssh目录权限设为700文件设为600尽量减少暴露面积。如果一台机器上有多套密钥比如一套用于登录实验室服务器一套用于登录某个云主机那建议不要覆盖默认文件名而是用-f参数指定ssh-keygen -t ed25519 -f ~/.ssh/lab_ed25519 -C lab-key登录的时候用-i指定密钥文件ssh -i ~/.ssh/lab_ed25519 userserver这里有个细节值得注意-i参数会覆盖默认的密钥查找路径所以如果你指定了密钥文件但私钥不在你指定的位置ssh不会自动去~/.ssh/id_ed25519找这一点在排查为什么我的密钥不生效时经常踩坑。2.3 私钥口令一道容易被忽略的防线生成密钥的时候ssh-keygen会提示你输入passphrase很多人直接按回车跳过了。我强烈建议不要跳过这一步。你可以把私钥文件本身理解成一把钥匙而passphrase是这把钥匙的保险锁。即使某天你电脑被植入恶意程序、私钥文件被窃取攻击者拿到私钥之后还需要passphrase才能使用它这给了你足够的时间去撤销公钥权限。输入passphrase的唯一不便之处是每次登录都要输入一次口令。解决这个问题有两个办法一是用ssh-agent把私钥加入到内存中登录时自动使用二是在后文会提到的~/.ssh/config中配合KeyChain管理。这里先记住一个原则私钥必须加密保存不加密的私钥等于裸奔。3. 将公钥部署到服务器简单操作背后的权限陷阱3.1 authorized_keys的追加与ssh-copy-id的使用密钥生成好之后需要把公钥内容放到服务器的~/.ssh/authorized_keys文件里。最简单的做法是使用ssh-copy-id命令ssh-copy-id -i ~/.ssh/lab_ed25519.pub userserver这个命令会要求你输入一次服务器密码前提是密码登录还没被禁用然后把公钥追加到服务器的authorized_keys文件里并且自动设置好权限。如果服务器上暂时没有密码登录条件也可以手动操作先在本地cat公钥内容然后登录服务器编辑~/.ssh/authorized_keys把公钥内容粘贴进去。但手动操作有风险——很容易因为换行、多余空格等问题导致密钥验证失败。3.2 权限不对密钥配置正确也会被拒部署公钥的过程中服务器端.ssh目录和authorized_keys文件的权限是最大的坑。OpenSSH对这个检查非常严格如果权限过宽它会直接拒绝使用该公钥进行认证而且日志里不会给你特别明确的权限不对提示。具体来说服务器端的~/.ssh目录权限必须是700~/.ssh/authorized_keys的权限必须是600或644但最稳妥的是600。如果权限不对最常见的现象是你输入的用户名密码是正确的服务端也看到你的公钥了但认证还是失败日志提示No supported authentication methods或者Authentication refused: bad ownership or modes。我自己在一次配置中犯过这样的错误在一台新机器上手动创建/home/xxx/.ssh目录时没有注意umask的默认值导致.ssh目录是755结果公钥放上去了怎么连都连不上。排查了很久才发现是权限问题纠正之后立刻就能登录。3.3 sshd_config的核心配置项与切换顺序服务器端OpenSSH的配置在/etc/ssh/sshd_config文件里有几个关键参数必须搞清楚配置项含义推荐值PubkeyAuthentication是否启用公钥认证yesPasswordAuthentication是否允许密码认证视情况而定验证通过后设为noPermitRootLogin是否允许root直接登录建议prohibit-password禁止密码但允许密钥AuthorizedKeysFile公钥文件的存放路径默认.ssh/authorized_keys即可我的推荐切换顺序是先保证密钥认证可用确认可以正常登录然后把PasswordAuthentication设为no再重启sshd服务重新开一个终端窗口测试登录确认密钥认证仍然正常确认无误后再退出当前会话。如果在步骤2之后贸然退出当前会话而且密钥认证又因为某些原因失效那你就只能通过物理控制台或者云服务商提供的前面板来修复了。所以务必留一个已登录的会话别关这是基本的保命操作。修改完sshd_config之后记得重启服务生效Debian/Ubuntu系用sudo systemctl restart sshd或sudo service ssh restart重启前可以用sshd -t检查语法避免配置写错然后把服务搞挂。4. 从报错到联机一次完整的密钥认证排错过程4.1 现象用户名密码正确但密钥登录始终失败有一次我在给一台新的测试服务器部署密钥登录执行完ssh-copy-id后在本地执行ssh -i ~/.ssh/test_key userserver结果直接弹回Permission denied (publickey)。当时我以为是公钥没写进去于是检查了服务器上的authorized_keys确定公钥内容已经在里面了但就是登录不了。这种情况下最忌讳的是瞎猜。正确做法是给ssh加-v参数看详细的认证过程ssh -v -i ~/.ssh/test_key userserver4.2 逐行解读ssh -v的输出问题定位的关键-v输出里有一堆调试信息我摘几个关键行来说明debug1: Offering public key: /home/user/.ssh/test_key ED25519 SHA256:xxxx debug1: Authentications that can continue: publickey,password这两行说明客户端尝试用私钥去挑战认证但服务器返回还可以继续认证意味着服务器拒绝了这把公钥。如果authorized_keys内容确实没写错问题基本就锁定在服务器端。继续看服务器日志。Debian/Ubuntu下执行sudo tail -f /var/log/auth.log或者CentOS/RHEL系sudo tail -f /var/log/secure这时候能看到类似这样的一行Authentication refused: bad ownership or modes for directory /home/user/.ssh看到这行就秒懂了——是权限问题。用ls -ld /home/user/.ssh一看目录权限果然是755而不是700。修正chmod 700 /home/user/.ssh chmod 600 /home/user/.ssh/authorized_keys再重新连接一次通过。4.3 其他常见的失败原因与对应的解决方式除了权限问题我还遇到过其他几种情况一并列出来公钥文件里如果有多个公钥检查有没有无意间被截断。有时候从终端复制公钥会被换行符截断导致一行公钥变成两行服务端解析时就会报错。修复方法是用编辑器打开authorized_keys确保每一条公钥都在独立的一行内完整无缺。客户端使用了错误的密钥文件。如果本地~/.ssh目录下有多个密钥ssh默认会依次尝试但当-i指定了具体文件时它就只尝试这一个。有时候你以为自己在用某个密钥实际ssh-agent里缓存了另一个就会导致混乱。用ssh-add -l可以列出当前ssh-agent里加载的密钥指纹确认一下到底用的哪把。服务器端禁用公钥认证或root登录限制。检查sshd_config里的PubkeyAuthentication是否为yesPermitRootLogin是否允许你所要登录的账户。如果这两个配置有问题同样会得到Permission denied (publickey)的结论。时钟不同步导致签名校验失败。这个比较隐蔽如果客户端和服务器时间差太多某些严格配置的系统会拒绝认证用date命令对比一下两端的系统时间即可。4.4 验证登录是否真的用了密钥而不是密码成功登录后如果想把密码认证彻底关掉需要先确认密钥认证是真的生效的而不仅仅是碰巧通过了某个已知密码的认证。方法很简单在服务器的sshd_config里临时把PasswordAuthentication no配上然后保持当前会话不退出再开一个新终端测试密钥登录。如果新终端能正常登录说明密钥链路完整可以放心使用如果新终端登录失败就回到前文步骤继续排查。另外登录成功之后可以通过执行systemctl status sshd或last命令查看登录记录确认确实是publickey认证而不是密码认证。5. 日常连机的效率技巧与安全上的进阶注意事项5.1 用~/.ssh/config给常用服务器配置别名每次登录都要输入ssh userfull-hostname.example.com -p 2222 -i ~/.ssh/lab_ed25519这种长命令时间长了确实挺烦。我习惯把所有常用的连接信息都整理到~/.ssh/config文件里看起来是这样的Host lab HostName 192.168.1.50 User zhangsan Port 22 IdentityFile ~/.ssh/lab_ed25519 Host cloud HostName example-cloud-server.com User admin Port 2222 IdentityFile ~/.ssh/cloud_ed25519 ServerAliveInterval 60配置好之后以后登录只需要ssh labconfig文件里还可以设置一些很方便的选项ServerAliveInterval表示每隔多少秒发送一次心跳包防止长时间空闲连接被中断Compression yes可以在网络慢时开启压缩LocalCommand可以在连接建立后自动执行本地命令但这个要慎用。5.2 私钥多机同步与ssh-agent的使用很多人的工作习惯是办公电脑上有一对密钥家里电脑也想要同样的密钥于是就把私钥拷贝到另一台机器上。坦白说这种做法有风险但如果你确实需要多机使用同一对密钥建议至少保留passphrase不要用无口令的私钥做分发。日常使用中我更推荐每个设备生成自己独立的密钥对然后在服务器上把多个公钥都加入到authorized_keys。管理起来虽然多了几个条目但好处是一台设备私钥泄漏时只需要从authorized_keys中删除对应的一条公钥就行不用全部重来。如果你不喜欢每次输入passphrase可以在本地启动ssh-agent并加载私钥eval $(ssh-agent -s) ssh-add ~/.ssh/lab_ed25519之后同一会话内的多次ssh连接就不需要重复输口令了。macOS用户还可以用ssh-add --apple-use-keychain把passphrase存入系统钥匙串这样重启电脑之后也不用重新输入。Linux桌面环境也有类似的密钥环工具但配置起来稍微麻烦一些。5.3 定期检查authorized_keys防止幽灵公钥残留这是个很容易被忽略的维护动作。团队协作时间长了有人离职、有人换电脑服务器上的authorized_keys会积累越来越多旧公钥。有些公钥可能对应已经丢失的私钥有些可能对应已经离开的人员这些都是安全隐患。我一般每隔一段时间会用awk {print $3} ~/.ssh/authorized_keys列出公钥注释检查一遍是否有陌生条目。如果发现某个注释对应的同事已经不在团队里了就删掉那行。此外把我自己的所有公钥做一个备份清单存到密码管理工具里方便随时对照。5.4 不要在传输和备份环节上犯低级错误最后说一个我在备份私钥时踩过的问题。为了方便我曾把~/.ssh目录压缩打包后放到了网盘同步目录里打算作为备份。事后越想越不对网盘同步工具实际上把私钥明文副本推到了云端这等于把钥匙配了一把放在公共寄存柜里。后来我换成用加密容器比如工具自带的加密卷保存私钥备份并且单独用高强度随机密码保护才放下心来。如果有跨机器的文件传输需求建议用scp或rsync配合密钥认证完成不要临时把PasswordAuthentication yes打开。文件传输本身是一条独立的主题但和密钥认证配合起来才是完整的高效工作流scp -i ~/.ssh/lab_ed25519 localfile.txt lab:/tmp/5.5 一点关于密钥密语双重认证的补充如果管理的服务器真的非常重要还可以考虑在服务端配置AuthenticationMethods publickey,keyboard-interactive这样用户必须先通过密钥认证再输入额外的一次性口令或验证码。这个做法等于在密钥之上再加一道保险适合生产环境的关键节点但对日常开发机来说有些重了视需求取舍就好。6. 我踩过几次坑之后对SSH密钥认证的真实体会折腾完这一轮我最大的感受是SSH密钥认证并不难难的是把细节处理好。权限、路径、配置文件、密钥类型、私钥保管、agent管理每一个环节看似简单但任何一个点疏忽了都会带来为什么连不上的困惑。给后来者的几个建议第一生成密钥时不要跳过passphrase花十秒钟设一道口令收益远远大于麻烦第二切换密钥认证前先确认流程完整再关闭密码认证永远保留一个已登录会话作保底第三私钥是一个需要认真对待的资产它不是普通的电脑文件泄漏的代价可能比想象中大得多。第四遇到认证失败时别慌加-v参数看调试输出配合服务器日志一行行排查远比瞎猜高效。SSH是现代服务器管理里绕不开的基础技能花点时间把密钥认证吃透后续无论是管理一台机器还是一百台机器都会轻松很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑