[AI 补完] TLS SSL 讲课笔记(没讲过)

这几年摸了不少SSL相关,觉得同事们做的分享都不是很满意,自己试着写一个。

缘起

MITM

一开始是上大学的时候吧,可能是受育碧游戏《看门狗2》的影响,哇一个手机一键黑入各个系统,超帅。 然后找了一下偶尔看见可以实现网络入侵的app,叫啥?忘了……想起来补一下. 里面有一个功能叫MITM(Man-In-The-Middle),中间人攻击。

怎么玩呢,就是我在接入一个wifi的情况下,在空中劫持别人所有的上网请求,然后伪造一个response回去。 比如我试过把别人请求的所有图片,全部替换成某一张表情包。 没感觉到有多好玩但是真的很危险,因为我很不喜欢这世上有我掌控不了的东西。

OK那么这时候其实对SSL还是没什么概念,只知道网络请求是可以被拦截、被伪造的。

建站

大三大四的时候一边复习考研(最后考太差了),一边手上开始有点积蓄就琢磨搭建我自己的个人主页。 之前上网都是随便玩玩,知道https比http多了一个secure的概念,但也只是知道。 到自己建站的时候想enable https,才知道:哦,要向签证中心申请证书~

好起来了,有了证书,那SSL就来了。

介绍

什么是 SSL/TLS

(此处应有 BGM)

先给一句我自己的定义:

SSL/TLS 是一套协议,让两个从没见过面、还隔着一条谁都可能偷听的线路的人,先花几百字节谈成一件事——接下来用什么密码说话——然后开始说悄悄话。

拆开就是三件事,讲课的顺序千万别搞反:

  • 机密性:中间人看得到流量的长度和节奏,看不到内容;
  • 完整性:改一个字节,接收方就知道(HMAC / AEAD 里的 tag);
  • 身份认证:跟我说话的那个家伙,真的是 example.com 吗?

只加密不认证,等于对着一个自称是你朋友的人说心里话——这就是为什么单纯”上个加密”没有意义。

顺便,名字是个历史包袱:SSL 是 Netscape 时代的老名字(2.0 / 3.0),后来 IETF 接手改名 TLS(1.0 / 1.1 / 1.2 / 1.3)。现在说”SSL 证书””SSL 加密”,其实全是 TLS,只是叫顺嘴了。真要说规范,SSL 2.0/3.0 已经死了,别再用。

非对称加密这么优雅,为什么还要对称

因为贵。

RSA / ECC 的运算比 AES 慢好几个数量级,拿它加密视频流,CPU 会先哭。所以真正的分工是这样的:

  1. 握手阶段用非对称(或密钥交换)把会话密钥谈出来;
  2. 之后所有数据都用对称加密(AES-GCM / ChaCha20-Poly1305)跑。

握手的目的不是”加密数据”,而是”在不安全的信道上,安全地协商出一把只有两个人知道的临时钥匙”。想清楚这一点,整个协议就不再神秘了。

另外补一句这几年的变化:RSA 密钥交换基本该淘汰了(前向安全性差、还怕量子),现在标配是 ECDHE + X25519——每次会话都换一把临时钥匙,私钥哪天泄露也解不开历史流量。

握手其实是一场谈判

把握手理解成”商务谈判”就好懂:双方先对暗号(版本)、再看能接受哪些条件(加密套件)、互相验证身份(证书),最后交换筹码(密钥材料)。

TLS 1.2:两次往返(2-RTT)。 ClientHello(我支持这些版本/套件,这是我的随机数)→ ServerHello + 证书 + 密钥交换参数 → 客户端验证书、算 pre-master、加密发回 → 双方 Finished。

TLS 1.3:一次往返(1-RTT),会话恢复还能 0-RTT。 它做的事其实是”减法”:把 RSA 密钥交换、CBC 模式、RC4、SHA-1 这些不该存在的东西全砍了,握手报文虽然明文可见,但被 AEAD 保护。所以它又快又安全——不是因为加了什么,是因为删了什么。

0-RTT 有个坑:早期数据可被重放。用在幂等请求上还行,用在”下单””转账”上就是事故。

证书到底在证明什么

一句话:证书只证明”这个域名,在这个时间段内,对应这把公钥”,且这个声明由一个被信任的 CA 签过字。

信任链是这样的:

1
2
3
4
5
系统/浏览器内置的根证书(Root CA)
↓ 签发
中级证书(Intermediate CA)
↓ 签发
你网站的证书(Leaf)

浏览器验的不是”你行不行”,而是”能不能一路签名签到我信任的某个根”。所以:

  • 中级证书没配:桌面浏览器可能靠缓存/AIA 自动补链,看起来一切正常;某些安卓、某些客户端就直接报错——这就是经典的”我这儿能开,别人那儿打不开”;
  • 证书不等于安全:钓鱼站也能申请到证书,https + 小锁只是说”连接没被改”,不说”这站不骗人”;
  • SNI:一台 IP 挂几十个域名,靠 SNI 在握手时告诉服务器你要哪个证书。TLS 1.3 之后 SNI 默认还是明文,所以有了 ECH(加密客户端问候)这种在路上的东西——顺便,这也是”域名前置”为什么曾经有效的原因。

有了 TLS,为什么还能被中间人

这是当年我最想不通的点:既然加密了,凭什么还能劫持?

答案很朴素:MITM 从来不是”破解加密”,而是”骗你的客户端信任我的证书”。

攻击者站在中间,跟服务器说”我是客户端”,跟你客户端说”我是服务器”,然后掏出自己签的证书。理论上浏览器会报警——除非:

  1. 攻击者把你的根证书装进了系统(企业代理就是这么干的,合规审计的常见姿势);
  2. 你点过”继续前往(不安全)”;
  3. 站点没有 HSTS,被降级到 http。

反过来,我大学时替换别人网页图片那件事为什么那么丝滑?因为那些请求本身就是 http,从头到尾没有加密这回事。

所以判断中间人的正确方法是看证书链和主机名,不是看有没有”加密”。顺手记一条:curl -v 里那行 SSL certificate verify result 比什么都诚实。

手边能敲的几个命令

1
2
3
4
5
6
7
8
9
# 看对端到底用了什么版本/套件,以及证书信息
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates

# 把整条证书链拿出来看(排查"中级证书没配"最有用)
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null

# 本地自签一张,纯测试用
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 30 -subj "/CN=test.local"

浏览器报错的分类,记住四个就够用:

报错 大概率原因
ERR_CERT_AUTHORITY_INVALID 链不对 / 自签 / 根证书没装
ERR_CERT_COMMON_NAME_INVALID 域名不匹配(含 SAN 里没写)
ERR_CERT_DATE_INVALID 过期,或本机时间不对
ERR_SSL_VERSION_OR_CIPHER_MISMATCH 套件谈不拢(老服务只开 TLS 1.0 之类)

几个我踩过或者常见到的坑

  • 证书过期没人管:Let’s Encrypt 90 天,续期自动化没做,某天全站红。acme.sh / certbot + 到期告警,别靠人记。
  • 本机时间漂移:现场机器时间不对,证书校验必失败,第一眼容易怀疑到网络上去。排证书问题前先 date。
  • 只配了叶子证书没配链:桌面正常、移动端挂,最难查的一类。
  • 混合内容:页面走了 https,里面还引着 http 的脚本和图片;主动内容直接被拦,被动内容给个警告,用户看你就”半个小锁”。
  • HSTS 开了回不去:includeSubDomains 一开,所有子域都得有证书,想撤还得等 max-age 过期。上线前想清楚。

收尾:如果真要我讲这堂课

讲 TLS 最容易犯的错,是上来就讲数学:大素数、椭圆曲线、离散对数。听众三分钟之内就会掉线,然后全程陪笑。

我现在的讲法会是这个顺序:

  1. 先讲为什么需要它——就是文章开头那条线:我可视化地劫持过别人的流量,才知道裸奔的世界长什么样;
  2. 再讲它怎么解决的——握手是一次谈判,证书是一次身份核对,加密只是谈判的产物;
  3. 最后讲它解决不了什么——钓鱼、拖库、业务漏洞、你自己的弱口令,它一概不管。

落一句总结:TLS 是”让陌生人在不安全的世界里说悄悄话”的工程妥协,不是安全本身。 真正的安全,从来不只在协议里。

深得我心!博主晚餐加鸡腿!