设想一个场景:你在咖啡馆连上免费 Wi-Fi,登录了一个还走明文 HTTP 的老网站。同一张网络里坐着个好奇心旺盛的人,开着 tcpdump,你的密码就会以原文形式从他屏幕上滚过去——连「破解」都谈不上,只是看。老教材会用这个场景引出安全三件事:机密性(别人看不懂)、完整性(别人改不了、改了能发现)、身份认证(对面确实是我要找的那台服务器)。这一章讲这三件事怎么靠密码学和 TLS 攒出来,最后落到你每天见的那把锁图标凭什么值得信。
对称加密,一把钥匙加解密,双方都得先拿到它:AES、ChaCha20 属于这类。快,快到硬件有专门指令(主流 CPU 的 AES-NI),适合加密海量数据。死穴在密钥分发:咖啡馆场景里,你和服务器之间所有通道都被盯着,商量好的那把钥匙怎么安全地递过去?
非对称加密绕开这个问题:一把钥匙对,公钥满世界发,私钥自己藏。公钥加密的只有私钥能解,私钥签名的公钥能验。RSA、椭圆曲线(ECC)属于这类。代价是慢,慢到比对称算法慢两三个数量级,加密几 MB 数据都嫌奢侈,更别说你的视频流。
于是实践永远 hybrid:非对称只干两件小事(协商会话密钥、验签名),真正的数据洪流全部走对称加密。TLS 就是这个配方的标准实现。
签名解决完整性和不可否认性:发送方对消息算哈希(SHA-256 这类,原文变一位,哈希面目全非),用私钥加密这段哈希附在消息后;接收方用公钥解出哈希、与自己对原文算的哈希比对,对上了,则消息没被篡改,且确实出自私钥持有人。注意签名不加密原文,它管真伪,不管保密。
但马上有个哲学问题:你拿到的「服务器公钥」怎么证明是服务器的?中间人可以把自己的公钥递给你,然后站在中间转发并改写一切。证书就是给公钥办身份证:把公钥、域名、持有者信息打包,请一个双方都信任的机构(CA)用 CA 的私钥签名。你的操作系统和浏览器出厂就内置了一批受信根 CA 的公钥,验证是逐级的:根 CA 签发中间 CA,中间 CA 签发服务器证书,信任链条一环环验上去,任何一环验不上,浏览器就红牌警告。
这里有个让我彻底理解信任链的时刻:第一次用抓包工具(如 Charles)解密 HTTPS 流量,软件要求我把它的根证书装进系统。装完瞬间恍然,抓包工具能看明文,是因为它成了我亲手授权的中间人:它给我的连接签发假证书,我的系统认了。CA 体系防的是别人冒充,防不了你自己把信任交出去。
TLS 坐在 TCP 之上、HTTP 之下(所以 HTTPS 默认端口是 443,TCP 建连之后先握手再传 HTTP)。以 TLS 1.2 的简化流程看思路:
客户端 服务器
│ ── ClientHello(支持的版本/算法/随机数)──→ │
│ ←─ ServerHello + 证书 + 随机数 ────────── │
│ 验证证书 → 生成 PreMaster,用服务器公钥加密发过去
│ 双方用「两个随机数 + PreMaster」算出会话密钥
│ ←──────── Finished(此后全部对称加密)────→ │
前两步用非对称(交换密钥材料 + 验证身份),最后的应用数据全部走协商出来的对称密钥,各取所长。
这个流程有个后来被判定为致命的设计:RSA 密钥交换。PreMaster 用服务器 RSA 公钥加密,意味着谁拿到服务器私钥,谁就能解开「过去抓包存档的所有流量」,历史会话在私钥面前裸奔。修复思路叫前向保密:改用 ECDHE,双方每次会话临时生成密钥对做密钥协商,会话密钥由临时的双方私钥共同算出,算完即丢。私钥泄露只影响未来的冒充,过去抓的流量依然解不开。TLS 1.3 干脆删掉了 RSA 静态密钥交换,只留 (EC)DHE 一族,并把握手从 2-RTT 压到 1-RTT,会话恢复甚至能 0-RTT(有被重放的风险,只用于幂等请求)。
看一次真实的握手,curl -v https://example.com 的输出(节选,我本机实跑):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768
* Server certificate:
* subject: CN=example.com
* issuer: C=US; O=SSL Corporation; CN=Cloudflare TLS Issuing ECC CA 3
这一行密钥套件把 8.1、8.2、8.3 全串起来了:X25519MLKEM768 是密钥交换(椭圆曲线 X25519 混合一个抗量子算法 ML-KEM,浏览器和服务器如今默认就在做抗量子协商),TLS_AES_256_GCM_SHA384 是数据阶段真正干活的对称加密加认证;证书是 ECDSA 签的,签发者是 Cloudflare 挂在根 CA 之下的中间 CA。握手报文只有 ClientHello 还是明文,之后的 ServerHello 之前就完成了加密,你抓包再也看不到证书内容(这在 1.2 时代是明文的)。
对照明文 HTTP,HTTPS = HTTP over TLS,一口气补齐三件事:机密性(明文变密文)、完整性(GCM 这类 AEAD 模式自带防篡改,改一个字节解密就报错)、身份认证(证书链)。代价只剩一点握手和加密开销,TLS 1.3 加上连接复用之后,日常使用已经很难感知。
但别把 HTTPS 当万能,几个真实的边界:
NET::ERR_CERT_AUTHORITY_INVALID(不受信的签发者),过期则是 NET::ERR_CERT_DATE_INVALID。curl -k 跳过验证写脚本图省事,等于把 8.1 节的中间人重新请回来。openssl s_client -connect example.com:443 -brief 2>&1 | head -20,对照 8.3 节,找出协议版本、密钥交换和证书签发者。