为什么 SSH 私钥在电脑,HTTPS 私钥在服务器?
从给服务器放一把公钥开始,弄懂登录、证书与加密文件
配置一台新服务器时,我在 Mac 上生成了一对密钥,把公钥放进服务器,私钥留在电脑上。
操作很短,疑问却很多:服务器只拿到公钥,怎么知道登录的是我?公钥既然可以公开,别人拿到了,为什么不能冒充我?还有,HTTPS 的私钥不是放在服务器上吗,怎么又反过来了?
先不碰数学。就从“放公钥”这一步,看看两台机器究竟在做什么。
往服务器放公钥,是在登记谁能登录
服务器不会因为有人知道它的地址,就允许对方进来。它需要一个判断依据。
密码登录的依据是:“你能不能提供这个账户的正确密码?”公钥登录则换了一种问法:“你能不能证明,自己持有这把公钥对应的私钥?”
因此,把公钥放进服务器账户的 authorized_keys 文件,相当于给这个账户登记一项登录资格:以后谁能证明自己持有对应的私钥,就可以通过这一项认证检查。 最终是否允许登录,还要符合服务器对账户和登录方式的配置。
此时,两边保存的东西是:
Mac 服务器
登录私钥 登记过的登录公钥
负责出示证明 负责检查证明
这里登记的是一把钥匙,并没有把权限永久绑定到 Mac 的硬件。另一台电脑如果拿到了同一把私钥,也可能以同样的方式登录。这才是私钥必须保密的原因。
登录时,Mac 发过去的是什么?
Mac 不会把私钥发送给服务器。它会在本机用私钥,对与这次连接、这次认证请求有关的数据生成一份证明。这份证明叫数字签名。
服务器拿登记过的公钥,检查这份签名是否与收到的数据匹配。匹配就说明:发起请求的一方能够使用对应的私钥。
可以把公钥理解成一个“检查工具”。它能回答“这份证明对不对”,却不能替你生成一份新的有效证明。验证的能力可以公开,出具证明的能力留给私钥持有者。 这是签名算法提供的核心能力。
普通手写签名可以拍下来复制,数字签名还和被签的数据绑定。换了数据,旧签名通常就不再有效。SSH 又把认证签名绑定到本次连接,所以即使别人拿到了上一次登录的签名,也不能简单复制它来登录新连接。
这就回答了两个问题:
- 为什么可以把公钥交出去? 拿到检查工具,不等于拿到了出具证明的能力。
- 为什么私钥留在 Mac? 发起登录的是 Mac,它需要在本机生成证明。目标服务器只需要检查,没有必要取得这把登录私钥。
注意,签名本身不负责隐藏内容。它回答的是“这份数据是否由对应私钥签出、有没有被改动”。SSH 的通信保密由另一部分机制完成;在进行用户认证之前,SSH 已经建立了加密传输通道。
HTTPS 看着反过来,是因为换了一方出示证明
现在离开终端,在浏览器里打开一个网站。
浏览器面对的问题变成了:“网络那一头,真的是我要访问的网站吗?”这次轮到网站出示证明,所以网站的私钥留在服务器上,浏览器取得对应的公钥来验证。
把两个场景并排放,会发现规则没有变:
| 场景 | 谁出示身份证明 | 私钥在哪里 | 谁用公钥验证 |
|---|---|---|---|
| SSH 的用户登录认证 | 登录者 | 发起登录的电脑 | 服务器 |
| HTTPS 的网站身份认证 | 网站 | 提供 HTTPS 的服务器 | 浏览器 |
我们之前拿来比较的,其实是两个不同方向的身份认证。
SSH 也要核验服务器身份。服务器有它自己的主机私钥,Mac 用对应的主机公钥检查它。因此同一条 SSH 连接里,可以同时存在“服务器证明自己”和“登录者证明自己”两件事,用的是各自的密钥。
第一次 SSH 连接时出现的服务器指纹提示,就与主机公钥有关。指纹是公钥的简短标识,需要通过可信来源核对;仅仅点击接受,并不能自动证明对方就是目标服务器。后续连接会检查主机密钥是否与已信任的记录一致。
HTTPS 也可以要求客户端出示证书,不过普通浏览网页通常不需要。网站里的账号登录,是后续由应用处理的另一件事。
网站说“这是我的公钥”,浏览器为什么信?
这里还缺了一步。
假如任何服务器都能递过来一把公钥,说“我就是你要找的网站”,即使它能证明持有对应私钥,也只能说明:它拥有这把钥匙。还没有证明这把钥匙属于那个域名。
HTTPS 用数字证书补上这层关系。
网站申请证书时,证书颁发机构,也就是 CA,会核验申请者对域名的控制权。验证通过后,CA 签发一张证书,把域名、网站公钥、有效期等信息放在一起,并加上自己的数字签名。
这里又用到签名了:CA 用自己的私钥签发,浏览器用相应的公钥检查,避免别人随意改写证书中的域名或公钥。
那浏览器凭什么信 CA?浏览器或操作系统预先内置了一批受信任的根证书。网站证书通常通过中间 CA,连接到其中一个受信任的根。浏览器沿着这条证书链验证签名,并检查域名、有效期等条件。最开始的信任来自浏览器或操作系统的信任配置,而不是某个机构单方面宣布“我值得信任”。
到这里,网站需要通过两道不同的检查:
- 证书检查: 这把公钥与正在访问的域名,是否有可信的绑定关系?
- 连接中的证明: 眼前的服务器,是否真的能使用对应的私钥?
证书可以公开,别人也可以复制它;只有证书,没有对应私钥,仍然无法完成正常的身份认证。CA 负责签发证书,不需要取得网站私钥,也不会因为签发了证书,就能读取网站与浏览器的通信。
因此,一个网站有有效证书,表示连接中的域名身份通过了验证。它不意味着网站卖的东西可靠,也不意味着里面的说法真实。
我们常说的“SSL 证书”是沿用下来的名称,现代 HTTPS 使用的是 SSL 的后继协议 TLS。
再换个场景:只让收件人读到一份文件
前面一直在讲证明身份。现在假设你要给朋友发一份文件,希望只有朋友能读到。
如果使用双方共用的密码,你得先想办法把密码安全地告诉朋友。公私钥提供了另一种办法:朋友保管自己的私钥,把公钥交给你;你使用他的公钥加密文件,他用自己的私钥解密。
可以把它想成朋友给了你一只打开的挂锁。你把文件装进盒子,扣上锁,就可以寄出去。别人拿到同样的挂锁,也可以锁一个新盒子,但不能因此打开你已经锁好的盒子。开锁的钥匙由朋友保管。
这个比喻只用来理解加密文件,别把它套到前面的数字签名上。两种用途的方向不同:
| 目的 | 公钥做什么 | 私钥做什么 |
|---|---|---|
| 让指定的人读到内容 | 发送者用收件人的公钥加密 | 收件人解密 |
| 让别人核验内容的出处 | 验证者用签名者的公钥检查 | 签名者签名 |
加密时,私钥在收件人那里;签名时,私钥在出具证明的人那里。判断放在哪台机器之前,得先判断它承担哪一种工作。
另外,你拿到的公钥必须确实属于朋友。如果有人把它换成了自己的公钥,你就可能把文件加密给错误的人。这与浏览器为什么需要验证网站证书,是同一类信任问题。
这就是非对称密码的基本思路
现在再看“非对称”这个名字,就容易一些了。
对称加密使用同一个秘密进行加密和解密;非对称密码使用一对有关联、作用不同的密钥。算法允许你公开其中一部分能力,同时保留另一部分能力。 你可以让别人加密给你,却不让他们解密;也可以让别人检查你的签名,却不让他们替你签名。
这依赖密钥之间经过设计的数学关系。在合适的算法和密钥长度下,生成密钥、加密解密、签名验证都能高效完成;仅凭公开信息反推出私钥,或伪造所需的证明,则没有已知的可行经典计算方法。理解它在工程里如何使用,到这一层就够了,不必先推导数学公式。
严格说,加密、签名、密钥协商属于不同功能,需要相应的算法,并非任意一对密钥都能包办所有工作。大家口中的“非对称加密”,有时是在泛指这一整类公钥密码技术。
实际传输大文件或网页时,还会搭配对称加密:先建立或保护一把临时密钥,再用它处理大量内容,效率更高。SSH、HTTPS 会协商通信所需的会话密钥;加密文件工具也常用公钥机制保护文件密钥,而不直接逐字加密整份文件。
还有哪些地方会遇到它?
软件更新。 下载到一个安装包,怎么判断它是不是发布方提供的、途中有没有被改过?发布方用私钥签名,设备用可信的公钥验证。所有人都可以下载同一个包,重点是核验出处和完整性。
Git 提交或软件发布。 一份提交写着某个作者的名字,不等于它一定由那个人创建。给提交或发布内容加上签名后,别人可以结合已信任的公钥核验来源。签名证明来源,不保证代码没有 bug。
端到端加密聊天。 两端设备利用公钥机制建立共享秘密,再用会话密钥保护消息。密钥属于谁、怎样核验联系人、换设备后怎样处理,会由具体聊天协议解决;仅仅写着“用了公私钥”,还不足以说明整个系统安全。
回到最初的服务器配置:我们交给服务器的是核验登录证明的工具,留在 Mac 上的是出具证明的能力。打开 HTTPS 网站时,轮到网站向浏览器出示证明;给朋友发加密文件时,保留解密能力的又变成了收件人。先看这一次究竟要完成什么,公钥和私钥的位置就有了理由。