SSH 的工作原理是什么?为什么它能安全登录、还能免密登录?
简化版
SSH(Secure Shell)是加密的远程登录协议(22 端口),用来安全地登录远程主机执行命令,取代了明文的 Telnet。它的安全靠三步:① 用非对称加密协商出一个对称密钥(后续通信全用对称加密,快);② 验证服务器身份(防连错/防中间人,靠首次记住的主机指纹);③ 验证客户端身份(密码或公钥)。免密登录的原理是公钥认证——你把自己的公钥放到服务器,登录时用私钥证明「我就是我」,服务器用公钥一验通过就放行,全程不传密码。
详细版
SSH 连接的三个阶段:
① 协商加密(建立安全通道)——先用非对称加密(如 DH/ECDH 密钥交换),让客户端和服务器在不安全的网络上安全地协商出一个共享的对称密钥(会话密钥)。之后所有数据都用这个对称密钥加密(对称加密快)。这一步保证了「传输内容不被窃听、不被篡改」。
② 服务器身份认证(防中间人)——服务器把自己的主机公钥发给客户端。客户端第一次连接时会显示指纹让你确认:
The authenticity of host 'x.x.x.x' can't be established.
ED25519 key fingerprint is SHA256:xxxx...
Are you sure you want to continue connecting (yes/no)?
你确认后,它把这个公钥记进 ~/.ssh/known_hosts。以后再连,若服务器公钥对得上就静默通过;对不上会强烈告警(可能是中间人攻击或服务器重装)。
③ 客户端身份认证(证明你是你)——两种方式:
- 密码认证:输入账号密码(在已加密的通道里传,安全,但仍要记密码、可被暴力破解)。
- 公钥认证(免密):用密钥对证明身份,不传密码,更安全也更方便。
免密登录(公钥认证)的原理:
① 本地生成密钥对:私钥(~/.ssh/id_ed25519,绝不外泄)+ 公钥(.pub)
② 把公钥追加到服务器的 ~/.ssh/authorized_keys
③ 登录时:服务器发个随机数,客户端用【私钥】签名,服务器用【公钥】验签
④ 验签通过 → 证明你持有对应私钥 → 放行,全程不发送密码
完整版教学
一、SSH 要解决的问题:Telnet 的裸奔
SSH 的存在,是为了干掉 Telnet 的致命缺陷——明文传输。Telnet 远程登录时,你的用户名、密码、敲的每一条命令、返回的每一行结果,全是明文在网上跑。任何能抓包的人(同一网络、路由器上)都能直接看到你的密码。
SSH 的目标就是把这条「远程登录 + 执行命令」的通道全程加密,并且双向验证身份——既确认「服务器是不是我要连的那台」(防中间人),也确认「登录的人有没有权限」。理解 SSH,就是理解它如何用密码学补上这三个洞:机密性、完整性、身份认证。
二、第一步为什么要「非对称换出对称密钥」
这是很多人绕不清的点:明明有非对称加密了,为什么还要协商一个对称密钥?
原因是性能:
- 非对称加密(RSA/ECC)安全但慢,加解密开销大,不适合给海量数据(你的整个会话)持续加密。
- 对称加密(AES 等)快,适合大量数据,但难题是「双方怎么在不安全的网络上安全地商定同一把对称密钥」——总不能明文发过去。
SSH 的解法是密钥交换算法(如 Diffie-Hellman / ECDH):它的神奇之处在于,客户端和服务器各自保留一个秘密、只交换公开信息,就能在数学上各自算出同一个共享密钥,而中间窃听者即使看到所有交换的公开数据,也算不出这个密钥。
于是:用非对称手段(DH 交换)安全地商定出一把对称会话密钥 → 之后用对称加密(AES)跑数据。既安全又快,这是几乎所有加密协议(包括 HTTPS)的通用套路。
三、第二步:known_hosts 与「中间人」的对抗
加密通道建好了,但还有个隐患:你连的「服务器」会不会是攻击者伪装的?(中间人攻击 MITM——攻击者夹在你和真服务器之间,两头都跟它加密,它就能看到明文。)
SSH 靠服务器主机密钥 + known_hosts来防:
- 每台 SSH 服务器有自己的主机密钥对。连接时它出示主机公钥。
- 第一次连接时你无从判断真假,SSH 让你人工确认指纹(理想情况下你应通过可信渠道核对),确认后把公钥存进
~/.ssh/known_hosts。这叫 TOFU(Trust On First Use,首次使用即信任)。 - 以后每次连接,SSH 都核对服务器出示的公钥和 known_hosts 里存的是否一致。一致 → 是同一台,放行;不一致 → 大声警告「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」——可能是中间人,也可能是服务器重装/换了密钥。
易错点:known_hosts 报警不总是攻击,服务器重装系统后主机密钥变了也会报。但在没搞清原因前,绝不能盲目删掉重连——那正是中间人希望你做的。
四、第三步核心:免密登录到底怎么「免密」
免密登录(公钥认证)是 SSH 最实用、也最爱考的部分。很多人以为「免密 = 把密码存起来自动填」,完全错——它压根不用密码,用的是非对称加密的签名验证。
准备阶段(一次性):
ssh-keygen -t ed25519 # 本地生成密钥对
# → 私钥 ~/.ssh/id_ed25519(保密!绝不外泄)
# → 公钥 ~/.ssh/id_ed25519.pub(可公开)
ssh-copy-id user@server # 把【公钥】追加到服务器 ~/.ssh/authorized_keys
登录时的验证(挑战-应答):
- 客户端告诉服务器「我想用公钥认证,这是我的公钥」。
- 服务器检查这个公钥在不在
authorized_keys里;在的话,发一个随机数(挑战)。 - 客户端用私钥对这个随机数签名,把签名发回。
- 服务器用对应的公钥验签。验签通过,说明对方确实持有配对的私钥,就是授权用户 → 放行。
关键点:私钥从不离开你的电脑,密码/密钥本身也从不在网络上传输。攻击者截获所有通信也没用,因为每次的挑战随机数不同,旧签名重放无效,而没有私钥就伪造不出新签名。
记忆抓手:公钥放服务器(锁),私钥留自己(钥匙)。登录 = 用私钥签名证明你有钥匙,服务器用公钥验锁。公钥泄露没关系,私钥泄露=大门洞开。
五、SSH 还能做什么:不只是登录
SSH 建的这条加密隧道用途很广,面试可加分:
- SCP / SFTP:基于 SSH 的加密文件传输(SFTP 就是 SSH 的一个子系统,走 22 端口,安全又不用管 FTP 的主动/被动模式)。
- 端口转发(隧道):把本地/远程端口通过 SSH 加密隧道转发,常用于安全访问内网服务、翻越网络限制。
- 本地转发
-L:把本地端口的流量,经 SSH 加密送到远端再转出去。 - 远程转发
-R:把远端端口的流量转回本地(内网穿透常用)。
- 本地转发
- 免密 + 跳板机(ProxyJump):通过堡垒机安全登录内网机器。
六、常见误区与追问
| 考点 | 正确口径 |
|---|---|
| 加密通道 | 协商会话密钥保护传输 |
| 服务器认证 | 客户端校验 host key 防中间人 |
| 用户认证 | 密码、公钥、证书等方式证明用户身份 |
client -> server: algorithm negotiation
key exchange -> session keys
verify server host key
user auth: password or public key signature
encrypted channel starts
SSH 安全不只靠密码,host key 防冒充,用户密钥防盗密,二者解决的问题不同。
- 误区:SSH 公钥登录是把私钥发给服务器。 私钥永远留在客户端,客户端用私钥签名,服务器用公钥验证。
- 误区:第一次连接的指纹提示可以永远忽略。 host key 指纹用于确认服务器身份,异常变化可能意味着中间人或服务器重装。
- 误区:SSH 加密后就不需要权限控制。 还要限制用户、sudo 权限、密钥权限、来源 IP 和审计日志。
- 追问:known_hosts 有什么用? 保存服务器 host key,后续连接发现变化会提示风险。
- 追问:公钥登录为什么比密码安全? 私钥不离开本机,可配 passphrase,抗暴力猜测能力更强。
- 追问:SSH 隧道是什么? 在 SSH 加密通道中转发本地或远程端口,用于安全访问内网服务。
七、加强记忆
SSH 是加密的远程登录协议(22 端口),取代明文的 Telnet。三步建立安全:① 密钥交换(DH/ECDH)协商出对称会话密钥(之后数据走 AES,快);② 靠主机公钥 + known_hosts 验证服务器身份(防中间人,首次 TOFU);③ 验证客户端身份(密码 or 公钥)。免密登录 = 公钥认证:公钥放服务器 authorized_keys、私钥留本地;登录时服务器发随机数挑战,客户端用私钥签名、服务器用公钥验签,全程不传密码,私钥绝不外泄。SSH 隧道还能做 SFTP、端口转发、跳板机。