1、TLS协议基础与握手流程

为什么说TLS是安全传输的基石?

你上网购物、登录邮箱、刷手机App,背后几乎都有TLS在默默工作。说白了,它就是给网络通信套了层加密外衣。早年间的HTTP是明文传输,谁在中间鼓捣一下,密码、卡号全暴露。我刚开始做安全运维的时候,还在用SSLV3,后来出了POODLE漏洞,整个行业才全面转向TLS。

TLS的核心能力,我总结了一下:

安全目标 解决什么问题 可以理解成
加密 数据在传输中不被偷看 把信装进保险箱
完整性 数据在传输中不被篡改 保险箱的封条,动了就知道
身份认证 确认对方就是你要找的人 看对方的身份证

这三个目标缺一不可。光有加密没有认证,骗子也能跟你握手;光有完整性没有加密,数据内容别人看得一清二楚。嗯,这里要记住:TLS不是单个算法,而是一套协议的组合。

我个人的理解:TLS就像一场交易现场——买卖双方先互相验明正身(证书),然后约定一套只有他俩知道的暗号(会话密钥),最后才放货(加密传输)。

从一次完整握手看TLS流程

握手,就是双方互相认识并约定加密方式的过程。我用一次典型的TLS 1.2握手给你拆开看。

  1. ClientHello:客户端先开口,告诉服务器自己支持哪些TLS版本、密码套件,附带一个随机数。
  2. ServerHello:服务器从客户端列出的选项里挑一套,返回自己的随机数和选定的密码套件。
  3. Certificate:服务器出示自己的数字证书,里面包含公钥和身份信息。
  4. ServerHelloDone:服务器说“我这边信息发完了”。
  5. ClientKeyExchange:客户端生成一个预主密钥,用服务器的公钥加密后发过去。
  6. ChangeCipherSpec:客户端说“接下来我要用约定好的密钥通信了”。
  7. Finished:客户端发一个加密后的握手消息摘要,服务器验证。
  8. ChangeCipherSpec + Finished:服务器也切换加密模式并发送自己的Finished消息。

为什么会这样做?每个步骤其实都在解决一个问题:如何让双方安全地共享一个大家都不知道的密钥。我曾经在一个项目里遇到握手反复失败,抓包一看,证书链不完整导致客户端一直不信任对方。从那以后,我排查握手问题时一定先看证书。

TLS 1.2完整握手流程图 客户端 服务器 1. ClientHello 2. ServerHello 3. Certificate 4. ServerHelloDone 5. ClientKeyExchange 6. ChangeCipherSpec 7. Finished 8. ChangeCipherSpec 9. Finished 加密传输阶段:应用数据使用协商好的对称密钥通信

小技巧:用Wireshark抓TLS握手包时,F5过滤表达式用tls.handshake.type。Type 1是ClientHello,Type 2是ServerHello,Type 11是Certificate。下次你自己抓包看看。

证书:握手中的身份证

你想想看,如果服务器随便发个公钥过来,你怎么知道它是淘宝而不是钓鱼网站?这就是证书发挥作用的地方。

数字证书本质上是CA(证书颁发机构)对网站身份的数字签名。它包含:

  • 持有者的域名、组织信息
  • 证书持有者的公钥
  • 证书的签发者(CA)信息
  • 有效期
  • CA的数字签名

客户端拿到证书后,会做几件事:

  • 检查证书是否在有效期内
  • 验证证书链,一直追溯到操作系统信任的根证书
  • 确认域名和证书的CN或SAN匹配
  • 检查证书是否被吊销

我在项目里遇到过不少证书相关的坑。有一次明明是正规的证书,客户端就是不认。抓包对比后发现是服务端只发了叶子证书,没发中间证书链。客户端找不到中间的CA,直接报错。

注意:证书过期了并不会影响加密过程本身,但客户端会拒绝继续握手。很多线上事故就是半夜证书过期导致的——别问我怎么知道的,经历过就是血泪史。

密码套件:协议的安全算法组合

TLS不只用一种加密方式,而是由多种算法组合成一个套件。一个典型的密码套件名字长这样:TLSECDHERSAWITHAES_128_GCM_SHA256

我来拆解一下:

组成部分 值 作用
密钥交换 ECDHE 协商出一个共享密钥,防前向安全
身份认证 RSA 用证书里的公钥验证数字签名
对称加密 AES_128_GCM 真正的数据加密,GCM模式同时提供完整性校验
哈希 SHA256 生成消息验证码(HMAC)

我个人习惯是这样:现代TLS配置首选ECDHE + AES-GCM。ECDHE提供前向安全,就算私钥泄露了,过去的会话也无法解密。RSA密钥交换已经不再推荐了——为什么?因为它不能提供前向安全。

# 查看服务器支持的密码套件
openssl ciphers -v | grep -i ecdhe

# 测试特定套件
openssl s_client -connect example.com:443 -cipher ECDHE-RSA-AES128-GCM-SHA256

实操:用Wireshark抓一次真正的握手

理论再好,不如动手抓个包看看。我建议你这样操作:

  1. 打开Wireshark,选择你上网的网络接口
  2. 用过滤条件 tls.handshake.type == 1 抓ClientHello
  3. 访问一个HTTPS网站(比如www.baidu.com)
  4. 观察客户端支持的密码套件列表,看看有哪些你认识的
  5. 再过滤 tls.handshake.type == 11 看服务器发来的证书
  6. 展开证书字段,查看Issuer、Subject、有效期、签名算法

初学者最容易忽略的是数据包的分片。有时候一个Certificate消息被分成好几个TCP段发过来。Wireshark会帮你重组,但你得知道原始结构是这样的。

避坑指南:我曾经在生产环境看到客户端和服务器握手成功,但业务就是报错。查了半天发现是TLS 1.3的0-RTT导致的重放攻击。有些负载均衡设备对0-RTT支持不够好——遇到这种问题,考虑降级到TLS 1.2做兼容。

这一章先打好基础。理解了握手过程,后面分析错误码和证书日志才能有的放矢。嗯,先动手抓个包感受一下。