简体中文
密钥登录也会被攻破?SSH 双因子认证到底补上了什么
很多人以为把 SSH 改成密钥登录、禁用密码,安全这件事就做完了。这个认知在"服务器不被爆破"这一层是对的,但它漏掉了一个更常见的失守路径:凭证本身被泄露。SSH 双因子认证(MFA)补的正是这个缺口——它不是让登录"更难猜",而是让"拿到了凭证"这件事不再等同于"能登录"。
密钥登录挡不住的一类攻击
先明确密钥登录解决了什么。公钥认证用非对称密钥对,登录时不传输私钥,只做一次签名校验,因此它对远程暴力破解基本免疫。SSH 登录日志里那些成百上千次的尝试,几乎全是冲着密码认证去的——把 PasswordAuthentication 关掉、统一走 SSH 代理接入(/zh/usage/ssh-server),日志会立刻安静下来。
但密钥登录有它的信任边界:它信任"持有私钥的人就是授权用户"。这层信任在私钥文件被偷、备份盘泄露、开发机被入侵、密钥在多人之间流转这几种情况下会失效。一旦私钥落入他人手里,服务器无从分辨对面是本人还是攻击者——因为认证凭证就是那把私钥本身。
密码登录的问题更直接:弱密码、跨站复用、撞库都能让攻击者"猜"进来。哪怕在 sshd 前面加了 fail2ban,也拦不住一个用正确密码一次登录成功的人。
私钥泄露在现实里几乎不靠技术手段,而靠流程漏洞:.ssh 目录被整个打包进镜像、私钥被随手贴进工单或聊天记录、内网共享盘上躺着带私钥的备份、离职同事的机器没回收。密码这边更常见的是复用——某个论坛小站被拖库,同一个密码被拿去试公司邮箱和服务器。这些场景的共同点是:攻击者拿到的不是"破解能力",而是"现成凭证"。
这类攻击的共同点是:攻击者拿到了"你知道的东西"(密码)或"你有的东西"(私钥),然后冒充你。单因子认证识别不了这种冒充——它只验证"凭证对不对",不验证"拿凭证的是不是本人"。
MFA 补的是哪个环节
双因子认证的核心不是"更难猜",而是把身份验证拆成两个互相独立的证明:
| 因子类型 | 例子 | 常见失守方式 |
|---|---|---|
| 你知道的(knowledge) | 密码、PIN | 撞库、钓鱼、偷窥 |
| 你有的(possession) | 手机上的 TOTP、硬件令牌、Passkey | 设备丢失、SIM 卡劫持 |
| 你是什么(inherence) | 指纹、面容 | 生物特征泄露 |
真正的 MFA 要求两类不同因子的组合,比如"密码 + 手机动态码"。如果只是"密码 + 密保问题答案",那还是同一种因子,挡不住撞库。
为什么多一层就有效?因为攻击者拿到密码的途径——钓鱼、撞库、泄露数据库——通常拿不到你的手机;反过来,偷走你手机的人通常没有你的密码。两个独立渠道同时失守的概率,远低于任何一个单独失守。这就是 MFA 的全部价值,没有更玄的东西。
TOTP 是怎么做到"离线也能验证"的
SSH 场景里最常见的 MFA 是 TOTP(Time-based One-Time Password),就是 Authenticator App 里每 30 秒变一次的那 6 位数字。它有个反直觉的设计:验证不需要服务端和手机之间有任何通信。
原理是共享密钥。注册时服务端生成一个随机密钥,用二维码让你扫进手机,之后两端各自持有同一份密钥。每次出码时,手机对"当前时间戳整除 30 秒"这个计数做哈希,截断成 6 位数字:
counter = floor(unix_time / 30)
digest = HMAC_SHA1(secret, counter)
code = dynamic_truncate(digest) % 1000000服务端拿到你输入的 6 位码,用自己持有的那份密钥按同样算法算一遍,对得上就通过。因为两边靠的是共享密钥和时间,而不是网络,所以手机在飞行模式下也能正常出码,服务端也无需向手机推送任何东西。这套算法是 RFC 6238 定的标准,6 位是最常见的默认(也允许 7、8 位),哈希默认 SHA-1,也有用 SHA-256 的变体。
这个设计也顺带解释了 TOTP 的两个已知弱点。一是时间漂移:手机和服务端时钟差太多就会验证失败,所以实现里通常允许 ±1 个时间窗口的容差。二是共享密钥可被复制:如果注册二维码被截屏外泄,攻击者就能生成一模一样的码——这正是实时钓鱼代理能中转 TOTP 的原因,下面会说到。
SSH 协议里没有"第二因子"这个字段
一个容易被忽略的事实是:SSH 协议本身并没有给"第二个验证步骤"预留字段。标准的 SSH 认证流程里,客户端提供用户名和一种认证方法(密码、公钥签名、键盘交互),服务端返回成功或失败,就这么一轮。
所以 MFA 从来不是"在 SSH 里加个参数"这么简单,而是在外层再包一道:
- PAM 层:sshd 调用 PAM,在公钥验证通过后,再要求一次 OTP,两次都过才放行。缺点前面说过——要逐台配置。
- 键盘交互(keyboard-interactive):用交互式问答承载 OTP,但兼容性和配置复杂度都不低。
- 网关 / 堡垒机层:客户端先连到堡垒机,在堡垒机上完成"密码/密钥 + OTP"两层验证,再由堡垒机代你连后端。这是目前最省心的做法,因为验证逻辑和后端服务器彻底解耦。
理解这一点,就能看懂为什么"在 sshd 上散装 MFA"和"在堡垒机入口统一 MFA"的体验差这么多:前者是在每台机器上手工包一层,后者是把这层统一做成了一道门。
MFA 挡不住的攻击,得先说清楚
MFA 不是万能盾。把边界讲清楚,才知道该往哪儿补:
- 已经登录的会话:MFA 只作用于"登录"这一刻。攻击者若拿到一个已建立的会话——被盗的终端、已授权的 SSH 连接——MFA 完全帮不上忙。
- 实时钓鱼代理(AiTM):攻击者架一个假登录页,把你的用户名、密码、TOTP 码原封不动转发给真服务器。你输的码是"新鲜"的,服务器照常通过,代理则把会话劫走。传统 TOTP 挡不住这类攻击;基于 WebAuthn 的通行密钥(/zh/usage/passkey)绑定了浏览器和源站,能显著抬高这层门槛。
- 设备被控:手机被木马控制,或 Authenticator 云同步账号被攻破,"你有的"因子也不再属于你。
所以更准确的表述是:MFA 把"凭证被盗"这一类攻击的得手率压下去了,但它解决不了会话层和端侧的问题。指望一个开关把安全问题清零,本身就不现实。
在哪个环节强制 MFA,差别很大
决定上 MFA 之后,下一个问题是在哪一道门上验证。同样是"加一层",落点不同,效果和维护成本差很多:
- 直接加在 sshd(PAM)层:每台服务器都要配,密钥分发、策略统一、登录失败排查全自己拼。机器一多,维护成本线性上涨。
- 加在接入网关 / 堡垒机层:所有 SSH 流量先汇聚到统一入口,在这一层验证 MFA,再按授权转发到后端资产。策略只维护一份,登录行为天然留下审计记录。
对多服务器、多成员、多角色的团队,后者的收益是决定性的。MFA 的"强制"只有集中在入口才有约束力——散在各台机器上总会有漏网之鱼:某台忘了配、某个旧版本 sshd 不支持你要用的认证方式。
这也是堡垒机在"特权访问管理(PAM)"语境里存在的原因:把认证、授权、审计三个动作从 N 台机器收拢到一个点上。以开源的 Next Terminal 为例,它支持在登录环节接入 OTP 二次认证(/zh/usage/otp)和通行密钥(/zh/usage/passkey),对资产访问(/zh/usage/access)统一施加双因子,登录与操作又能对应到等保/内审需要的审计记录(/zh/usage/compliance)。这套"入口集中验证"的思路和同类产品大同小异,换其他堡垒机也能照搬。
落地前必须想清楚的三个代价
MFA 的收益很明确,但它是拿成本换来的,上线前有几个坑要提前排:
- 锁死与恢复通道。TOTP 依赖手机,手机丢了、换机了、时间飘了,人就进不去了。必须设计恢复机制(备用码、管理员重置、恢复密钥),否则 MFA 会从安全措施变成"把自己锁在外面"的事故源。
- 自动化怎么办。CI/CD、脚本、备份任务靠密钥做无交互登录,给它们硬加交互式 MFA 会直接打断流水线。通常做法是区分"人"和"机器"两类身份:人走 MFA,机器走限定来源 IP + 短生命周期凭据,而不是一刀切。
- 用户体验的摩擦。每登录一次就掏手机输 6 位码,高频操作的人会烦,烦了就会想办法绕过。合理的设计是"低风险操作少打扰、高风险操作二次确认",而不是把摩擦均匀铺满每一步。
这三个代价想清楚,MFA 才能从"合规要求"变成真正在用的东西。
什么情况下 MFA 是刚需
最后落回一个能拿着做决策的判断。满足下面任意一条,MFA 的优先级就该排到前面:
- 成员能从公网登录服务器,而不是只能在办公网内。
- 密码或密钥存在共享 / 流转的情况,哪怕只是"临时借一下"。
- 服务器上跑的是生产数据、客户数据、支付相关的资产。
- 有合规 / 等保 / 审计要求,需要证明"登录动作是本人做的"。
反过来,如果只是个人局域网里的几台实验机、登录来源固定且不达公网,MFA 的收益就抵不过它带来的摩擦。
关键不在于"用不用 MFA"这个二选一,而在于先认清自己的信任边界塌在哪:凭证容易泄露,就上双因子;会话容易泄露,就去治会话和端侧;根本没有审计,就先让每一次登录都有据可查。把问题拆对,工具才不会用错地方。