ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SSH登录报Permission denied?从ssh -v到服务端日志的完整排查指南

SSH登录报Permission denied?从ssh -v到服务端日志的完整排查指南 1. 先分清密码错了还是根本没走到密码验证这一步如果你跟我一样经常跟远程服务器打交道那Permission denied, please try again这行提示估计早就不陌生了。说句实话这东西出现的频率高到我都快把它当开机问候语了但它背后的原因其实千差万别——密码不对会报这个密钥不行会报这个服务端配置有问题还是报这个。很多新手看到这行字就下意识觉得我密码输错了但实际排查下来真正输错密码的情况反而只占一小部分。我用个生活化的类比来解释一下。你在小区门口按门铃里面传来一句您哪位我没听说过您。这个回复放在不同场景下可能是保安真的不认识你也可能是保安今天换了人、访客名单被撕了、甚至是对讲机坏了导致他压根听不清你喊的什么。SSH的Permission denied也一样只是server端统一对外说的一句我不认你至于为什么不认你它不会在默认情况下告诉你。先别急着改配置第一步是把客户端日志等级拉起来先确定这个denied发生在哪个阶段。最简单的办法就是登录的时候加一个-v参数或者更暴力一点直接上-vvvssh -v useryour-server-ip ssh -vvv useryour-server-ip别小看这一个参数。加了之后SSH客户端会把整个握手过程的所有事件都打印出来包括连上了哪个IP、交换了什么算法、用的是哪种认证方法。你在输出里会看到类似这样的内容debug1: Authentications that can continue: publickey,password debug1: Next authentication method: publickey debug1: Trying private key: /home/me/.ssh/id_rsa debug1: Authentications that can continue: publickey,password debug1: Next authentication method: password这段输出的信息量非常大。它告诉你两件事第一服务器当前允许的认证方式有哪几种第一行的publickey,password就是服务器愿意接受的方式第二客户端依次尝试了哪些方式。如果你看到Authentications that can continue后面列出的方式里压根没有password那你密码输一万遍也是白搭因为服务器根本不接受密码认证这条路。我也遇到过不少朋友上来就改服务端配置折腾半天最后发现是自己客户端指定了错误的私钥文件。先在客户端把日志打开确认问题出在哪一层这是整个排查过程里性价比最高的一步。2. 密码登录被拒三类最容易被忽视的配置级原因如果ssh -v已经确认服务器允许密码认证而且你确定密码也没输错那问题大概率出在配置层。这里我按我平时排查的经验把最常见的三类原因整理出来。2.1 PasswordAuthentication 被关闭这是最经典的一个坑。很多人为了让服务器更安全按照网上教程把/etc/ssh/sshd_config里的PasswordAuthentication改成了no结果自己也忘了这茬下次登录的时候就莫名其妙被拒了。这个配置项的含义是一刀切地允许或禁止密码认证。改成no之后所有用户都不能用密码登录只能走密钥。如果你恰好还没把公钥部署上去那基本就是把自己锁在门外的节奏。那怎么确认是不是这个原因回到上面说的-v输出debug1: Authentications that can continue: publickey如果你看到括号里只剩publickey没有password那十有八九就是PasswordAuthentication被关掉了。解决方式也简单有权限的话直接改回yes或者从有密钥的机器上登录进去改。这里我强调一句改完配置文件之后一定要先测试再重启服务避免把自己锁死。正确的姿势是sshd -t这个命令会校验配置文件的语法如果有语法错误会直接报出来。确认无误后再重启sudo systemctl restart sshd # 或者 sudo service ssh restart2.2 PAM 模块与 ChallengeResponseAuthentication 的联动影响大部分老手都知道PasswordAuthentication但很多人忽略了ChallengeResponseAuthentication这个兄弟配置项。在某些 Linux 发行版和 SSH 版本里密码认证其实走的是键盘交互keyboard-interactive通道而键盘交互又受 PAM 模块控制。如果ChallengeResponseAuthentication被设成了no或者 PAM 配置出了问题同样会出现密码明明正确却提示Permission denied的情况。我遇到过一例非常典型的场景一台 Ubuntu 18.04 服务器用户密码没问题PasswordAuthentication也是yes但所有用户都登录失败报 Permission denied。后来我用ssh -vvv userserver看了一眼输出发现它卡在keyboard-interactive这个认证方法上而且服务器端日志里出现了 PAM 相关的报错。查了半天最后发现是/etc/pam.d/sshd里有一行配置被某个安全加固脚本改动过导致 PAM 无法正常校验密码。这种问题单看 SSH 配置是完全看不出来的必须结合服务端日志才能定位到。给普通用户一个更直观的判断方法在ssh -v输出里如果看到Next authentication method: keyboard-interactive然后紧接着就 Permission denied那你就要考虑 PAM 层面的问题了。2.3 密码里带特殊字符的灵异事件这个说出来你可能觉得不可思议但我确实遇到过不止一次。用户密码里有$、!、这类特殊字符在终端里输密码的时候被 shell 或终端工具吃掉了一部分导致实际发送到服务器的密码跟真实密码不一样。比如密码是Passw0rd!$ecure在某些终端环境或 SSH 工具里!可能触发 shell 的历史替换$开头的内容可能被当作变量解析。虽然很多终端不会在处理密码输入时启用这类功能但如果你用的是某些较老的终端工具、或者密码是从其他地方复制粘贴进来的粘进来的时候被中间层转义修改也不是完全没可能。应对方法是啥简单粗暴优先使用支持直接交互输入密码的方式不要通过sshpass这类工具把密码作为命令行参数传如果要用sshpass也一定注意转义问题。另外我个人的习惯是确认密码本身没问题后再考虑是不是特殊字符在作怪——别在没确认密码正确之前就去改服务器配置。3. 密钥认证失败权限、路径与 known_hosts 的连环坑现在越来越多的同学用密钥登录因为确实比密码方便也更安全。但密钥认证报Permission denied的频率说实话一点都不比密码低。每次帮人排查这类问题我基本上都会按下面这条链路走一遍。3.1 目录和文件权限不对私钥直接不生效SSH 对密钥文件的权限要求非常严格这是出于安全考虑——如果私钥文件权限太宽松任何人都能读你的私钥那密钥认证还有啥意义。OpenSSH 会直接拒绝使用权限过大的私钥文件。具体标准是这样的~/.ssh目录的权限必须是700drwx------~/.ssh/authorized_keys文件的权限必须是600-rw-------私钥文件的权限也应该是600不能是644或更宽松的权限这个规则很多从 Windows 转过来的同学特别容易踩坑。Windows 文件系统没有 Unix 那套权限模型用某些工具生成的密钥文件上传到 Linux 服务器之后默认权限可能是644甚至755OpenSSH 直接拒绝使用。如果你在-v输出里看到类似这句话debug1: Will attempt key: /home/me/.ssh/id_rsa debug1: Trying private key: /home/me/.ssh/id_rsa然后下一行又出现了Authentications that can continue而没有Server accepts key之类的字样那基本可以断定服务器没接受这个私钥。这时候先在客户端这边检查一下本地私钥权限ls -la ~/.ssh/ chmod 700 ~/.ssh chmod 600 ~/.ssh/id_rsa再去检查服务器端authorized_keys的权限因为服务端同样对~/.ssh目录和authorized_keys文件权限敏感。我之前见过一个情况服务端authorized_keys文件权限是664组用户可写结果 SSH 直接忽略了这个文件怎么登录都提示 permission denied改成600之后立刻恢复。3.2 authorized_keys 文件的格式与换行坑有一个问题特别隐蔽当你把自己的公钥粘贴到服务器的~/.ssh/authorized_keys文件时如果粘贴过程把公钥内容折行了、或者文件末尾没有换行符可能导致公钥无法被正确解析。authorized_keys文件要求每行一条公钥不能有换行截断不能有多余的引号或特殊字符。我还见过一种更隐蔽的情况公钥内容看起来对但实际粘贴进去的时候混入了不可见字符比如全角空格。这种情况下用cat看文件内容完全正常但 SSH 解析就是不通过。排查手段很笨但很有效把authorized_keys文件清空用命令行方式重新写入公钥避免复制粘贴过程引入隐藏字符。mkdir -p ~/.ssh chmod 700 ~/.ssh echo ssh-rsa AAAA...你的公钥内容... userhost ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这里注意一下公钥内容必须是完整的一行不能有换行。你可以在本地用cat ~/.ssh/id_rsa.pub看输出然后通过ssh-copy-id自动部署ssh-copy-id -i ~/.ssh/id_rsa.pub userserver-ipssh-copy-id这个工具比我手动粘贴省心得多它自己会处理好权限问题不需要我每次手动chmod。3.3 重启实例或重装系统后主机密钥变化导致的拒绝还有一种经常让人抓狂的情况服务器之前用密钥登录是好的某天突然重启或者从镜像恢复之后再用原来的密钥登录就报 Permission denied。这里涉及到一个概念叫主机密钥host key。SSH 协议在设计时客户端会保存一份服务器的公钥指纹就是known_hosts文件里那一堆内容用于防止中间人攻击。当你重新安装系统、或者某些虚拟化平台重置了实例服务器的主机密钥变了客户端识别出这跟我之前认识的服务器不是同一台出于安全考虑就会拒绝连接。这个报错信息其实很直白通常会提示你WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!但有些情况下客户端配置了StrictHostKeyChecking的某些选项或者利用某些跳板工具错误信息会被简化最终落在Permission denied上。如果你确认服务器的确是同一台、只是系统重装过那解决方案是把known_hosts里对应的那一条删掉重新连接ssh-keygen -R server-ip这样就会清除known_hosts中关于这个 IP 的旧指纹记录下次连接时重新接受新的主机密钥即可。4. 服务端账户与软件层面的隐形因素很多时候客户端这边查了半天都没问题这时候就该把目光转向服务端了——账户本身的状态、远程管理工具的介入、甚至安全防护软件的行为都会让 SSH 登录显示成同样的一句 Permission denied。4.1 root 登录受限与 shell 异常很多服务器默认配置下PermitRootLogin是prohibit-password或者no。如果你习惯直接用 root 账号登录而这个值是no那无论你密码对不对服务端一律拒绝。这种情况在-v输出里能看到Authentications that can continue列表中没有 password或者有但随即被拒而服务端日志里会有很明确的提示。Shell 异常这个坑也值得单独拿出来说。我遇到过一次非常诡异的情况用户反馈 SSH 登录被拒但我用另一个账号能正常登录进去。查了半天原来这个用户的登录 shell 在/etc/passwd里被改成了一个根本不存在或者没有执行权限的路径SSH 在认证成功之后尝试启动 shell 失败最终对外呈现的也是连接被中断或拒绝。排查方法很简单cat /etc/passwd | grep username看看该用户行最后一个字段就是登录 shell指向哪里。如果是/bin/false、/sbin/nologin、或者某个不存在的路径那这个用户默认就是无法登录的。有些运维人员为了禁用某个账号会把 shell 改成 nologin但忘了这个账号可能还有业务用途。4.2 fail2ban 等防护工具把人拉黑的连锁反应这个东西我吃过好几次亏。服务器部署了 fail2ban 或者 DenyHosts某个账号密码连续输错几次之后IP 被临时封禁或服务被暂时锁住。结果是你后面哪怕输入了完全正确的密码同样也提示 Permission denied。这种场景的排查尤其需要冷静。如果你已经确认密码、密钥、配置全都正确但还是被拒可以换个网络环境比如用手机热点试试。如果换了网络就正常了那九成是当前 IP 被某种防护机制盯上了。到服务器上执行sudo fail2ban-client status sshd就能看到哪些 IP 被 ban 了。还有一种相似的情况是 PAM 的pam_faillock或pam_tally2模块在起作用连续失败后锁定账号即使密码正确也没用。这时候用有权限的账号比如从其他 IP 或控制台解锁sudo faillock --user username --reset说起这个我强烈建议大家在遇到 SSH 登录问题时先看一眼系统时间是否准确。我知道这听起来跟问题毫无关联但 SSH 协议里有时间戳校验机制客户端与服务端时间偏差太大会导致认证过程中的某些校验步骤异常表现出的错误同样五花八门。我排查过一起密钥登录间歇性失败的怪事最后发现就是服务器时间漂移了。4.3 SSH 服务的监听地址与防火墙策略还有一个容易被忽略的点sshd_config里的ListenAddress。如果服务器配置了多个 IP而ListenAddress只绑定了其中一个你连的是另一个 IP连接可能直接超时也可能在特定情况下出现认证异常。防火墙策略同理某些安全组规则只允许某个来源 IP 访问 SSH 端口其他来源一律拒绝或丢包。这类问题的特点是现象不稳定有时候能通有时候不能通或者只有特定网络环境下才有问题。挨个检查一圈之后建议用nc -vz server-ip 22先确认端口可达性再去深究认证层面的原因。5. 从 ssh -vvv 到服务端日志一套完整的排查链路前面聊了这么多具体的场景这里我把自己平时碰到这个报错时执行的完整排查链路整理出来。越是这种看似简单的报错越需要有章法地排查否则很容易东一榔头西一棒子浪费时间还找不到根因。第一件事永远先在客户端确认问题出在哪个阶段。执行ssh -vvv userserver-ip重点关注三段输出第一段是连接建立阶段看 TCP 是否连通、版本协商是否正常。如果卡在这里是网络层问题。第二段是算法协商和主机密钥验证看是否报 host key 相关错误。如果卡在这里是 known_hosts 或中间人问题。第三段是认证阶段看Authentications that can continue列出了哪些方法。这里能直接判断是密钥问题、密码问题、还是服务器根本不给你用某些认证方式。第二件事确认客户端没问题后立刻转到服务端查日志。Ubuntu/Debian 系列看sudo tail -f /var/log/auth.logCentOS/RHEL 系列看sudo tail -f /var/log/secure服务端日志包含的信息量远大于客户端。它会明确记录认证失败发生在哪一步比如Invalid user xxx、Failed password for xxx、Connection closed by authenticating user xxx、error: maximum authentication attempts exceeded等等。这些不同的关键词对应的排查方向完全不同日志关键词说明排查方向Invalid user用户不存在确认用户名是否拼写正确Failed password密码验证失败确认密码、PAM 配置、特殊字符Connection closed by authenticating user认证过程中连接被关闭检查密钥格式、authorized_keys 权限maximum authentication attempts exceeded认证尝试次数超限客户端指定了大量无效密钥文件Received disconnect from ...服务端主动断开检查防火墙、fail2ban、TCPWrapper第三件事如果日志里也没有明确线索就需要做最小化验证。所谓最小化验证就是绕过所有可能出问题的环节用最原始的方式测试。比如关闭客户端的~/.ssh/config配置影响用ssh -F /dev/null userserver-ip绕过自定义配置。只指定一个密钥文件尝试登录ssh -i ~/.ssh/id_rsa -o IdentitiesOnlyyes userserver-ip。绕开可能的网络因素在服务器本机执行ssh userlocalhost测试本机上的 SSH 服务是否正常。我之前排查过一例客户端报 permission denied但服务器本机ssh userlocalhost正常。最后发现是客户端的~/.ssh/config里配了一个ProxyJump流量被转发到了一个错误的中转服务器上等于一直在跟错误的机器握手。这种问题不看配置根本不可能想到。第四件事如果以上全部正常最后再考虑改配置。改配置前一定先做备份sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date %F)然后逐项确认关键配置sudo sshd -T | grep -E permitrootlogin|passwordauthentication|pubkeyauthentication|challengeresponseauthentication注意用sshd -T而不是直接cat配置文件。因为sshd -T会展开所有 include 文件的结果输出的是 sshd 实际生效的配置而不是表面看到的文件内容。很多配置文件里有Include /etc/ssh/sshd_config.d/*.conf这样的行你改的是主配置文件但某些配置项可能被追加配置文件覆盖了这是 Linux 系新版 OpenSSH 特别常见的一个坑。6. 我踩过的坑和最后的经验总结按惯例最后分享几个我实际遇到的、不在常规排查清单里的小众情况。第一个是 SELinux 上下文问题。CentOS 7 以上如果开启了 SELinux即使文件权限全对SELinux 的安全上下文不对也一样登录不了。这种情况在tail -f /var/log/audit/audit.log里能看到denied相关的记录。我曾经帮朋友处理过一台服务器所有配置检查了 N 遍都对最后发现是根目录下.ssh目录的 SELinux 上下文不对执行restorecon -R -v ~/.ssh才彻底解决。这个问题坑就坑在普通排查手段根本看不到异常只有看审计日志才能发现。第二个是关于多个公钥的坑。有时候你本地~/.ssh下有好几个密钥文件SSH 客户端默认会依次尝试所有密钥。如果第一个密钥被服务器拒绝客户端不会立刻跳过而是继续尝试下一个。但如果服务器配置了MaxAuthTries限制默认是 6尝试次数超过上限即使最后一个密钥是正确的也会被踢掉。解决方案是在客户端~/.ssh/config里明确指定使用哪个密钥Host myserver HostName 192.168.1.100 User myuser IdentityFile ~/.ssh/my_special_key IdentitiesOnly yes第三个是关于 SSH 配置文件里PermitRootLogin和 PAM 的组合问题。有个版本比较老的操作系统上即使设置了PermitRootLogin yes如果 PAM 的/etc/pam.d/login里有pam_securetty模块拦着 root 从伪终端登录root 依然登不上去。这时候securetty文件里需要添加对应的 tty 名称或者把pam_securetty那行注释掉。说了这么多其实最核心的体会就一句话Permission denied, please try again是 SSH 对外统一的一张冷脸它把内部的所有拒绝原因都掩盖了。不要在旁边瞎猜按客户端是否允许认证 → 密钥是否被认可 → 密码是否正确 → PAM 是否放行 → 防护策略是否拦路这条链路逐级排查配合ssh -vvv和服务端日志双管齐下这个报错背后的真实原因基本没有藏得住的。最后再啰嗦一句改任何服务端配置前先把用户和当前连接备份好别把自己锁在门外这是我见过最多、也最让人哭笑不得的运维事故了。
返回列表