惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Hackread – Cybersecurity News, Data Breaches, AI and More
W
WeLiveSecurity
C
Check Point Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost
GbyAI
GbyAI
A
Arctic Wolf
NISL@THU
NISL@THU
N
Netflix TechBlog - Medium
The Register - Security
The Register - Security
M
MIT News - Artificial intelligence
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Microsoft Security Blog
Microsoft Security Blog
Cyberwarzone
Cyberwarzone
C
CERT Recently Published Vulnerability Notes
T
Tenable Blog
G
GRAHAM CLULEY
O
OpenAI News
S
Schneier on Security
Google Online Security Blog
Google Online Security Blog
Vercel News
Vercel News
宝玉的分享
宝玉的分享
Attack and Defense Labs
Attack and Defense Labs
T
The Blog of Author Tim Ferriss
量子位
aimingoo的专栏
aimingoo的专栏
The Cloudflare Blog
P
Privacy & Cybersecurity Law Blog
S
SegmentFault 最新的问题
MongoDB | Blog
MongoDB | Blog
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 热门话题
博客园_首页
F
Full Disclosure
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Docker
U
Unit 42
A
About on SuperTechFans
博客园 - 司徒正美
Hacker News - Newest:
Hacker News - Newest: "LLM"
人人都是产品经理
人人都是产品经理
Application and Cybersecurity Blog
Application and Cybersecurity Blog
G
Google Developers Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
J
Java Code Geeks
云风的 BLOG
云风的 BLOG
Scott Helme
Scott Helme
TaoSecurity Blog
TaoSecurity Blog

Razeen`s Blog

Let's Encrypt 推出 Gen Y 根证书架构:揭示 Web PKI 的五大未来趋势 通过 Wi-Fi 自动备份你的 iPhone 到 Nas 管理培训感悟:从技术视角看管理之路 UPS 一拖多:保护你的 NAS 和 Linux 服务器 从影音中心到 AI 助手:我的50款 Homelab 服务清单 从SSL证书有效期将缩短到47天聊开去 部署一个自己的 Running Page 谈谈特斯拉 Model Y 用车一年的感受和费用分析 弃用 Disqus 评论,使用自建 Waline 使用 Prometheus 和 Grafana 搭建你的证书监控面板 服务器迁移记:一次磁盘换板引发的Linux分区与挂载的学习 改善信息来源, 利用 RSS 高效获取资讯 (RSShub + Reeder5 + WeWe RSS) 多种 Docker 镜像拉取解决方案与实践 App分享 | AppCleaner - Mac上的卸载神器 Azure OpenAI API 申请和使用 如何开通 OneKey 虚拟信用卡,并充值消费 如何拥有一个可长期在国内使用的国外手机号码 分享开通 ChatGPT Plus 过程 如何开通 Depay 虚拟信用卡,并充值消费 如何开通欧易Web3钱包, 交易入账 如何5分钟内1块钱注册 ChatGPT 如何注册美区的 Apple ID (2023年/无需科学上网) NAS折腾记(11): NASTool3.0体验和降级 NAS折腾记(10): Docker版本的NASTool配置 NAS折腾记(9): NASTool与微信交互,微信发送消息远程下载电影【多图】 NAS折腾记(8):群晖安装 NASTool 实现影音半自动化【多图】 内网穿透(2):Tailscale 组网实现内网穿透,操作简单,无成本 内网穿透(1):总结了11中内网穿透的方式,总有一种适合你 NAS折腾记(7):从零开始设置(黑)群晖系统 NAS折腾记(6):黑群晖系统安装好后怎么洗白? NAS折腾记(5):群晖硬盘休眠设置与分析 NAS折腾记(4): 20分钟手把手带你完美安装 DS918+ 黑群晖7.1.1 NAS折腾记(3):NAS 装机 NAS折腾记(2):B360-ITX 双M.2 双2.5G网口 6 SATA主版 开箱 NAS折腾记(1):328元的4盘位Nas机箱开箱 Openwrt + Clash 全局科学上网 Newifi3 刷入 OpenWrt 固件 v21.02 利用 Markdown 画一些流程图、时序图、甘特图等 Homelab(8): 搭建自用 Gitlab 与 Docker 仓库 Nginx Tcp 转发保留客户端真实 IP (PROXY Protocol) Homelab (7):IPSec VPN(基于证书认证)客户端设置 Homelab (6): 基于自签发证书的 IPSec VPN 搭建 Homelab (5): DDNS 动态域名解析 Homelab (4): Linux 服务器基础环境准备 Homelab (3): 整体网络与基础硬件介绍 Go学习笔记(十)老项目迁移 go module 大型灾难记录 Github Actions 初体验之自动化部署 Hexo 博客 记一次 Nginx DNS 缓存导致转发问题 Homelab (2): 电信悦me网关修改桥接模式,路由器拨号 Homelab (1):5分钟上手黑群晖 NAS 终极 Bash 脚本指南 Typora 自动上传图片到七牛云 Ubuntu 20.04 LTS 有线网卡驱动安装 折腾 Ubuntu 20.04 LTS 开发环境 Go学习笔记(九) 计时器的生命周期[译] 利用 git hook 规范你的代码与 commit message 规范 git commit message 与自动化版本控制 超详细 vim 配置 (with MacVim) Golang 中的 RESTful API 最佳实践 折腾服务器(开篇) 我的第一台个人服务器 Newifi3 实现低成本家庭级科学上网 Go学习笔记(八) | 使用 os/exec 执行命令 如何用 Go 调用 Windows API Mac OS 自动根据 WI-FI 名字改变网络位置 关于 Docker 清理 MIME Types 速查表 Go学习笔记(七) | 理解OAuth 2.0并实现一个客户端 我又又又把博客迁移了 Go学习笔记(六) | 使用swaggo自动生成Restful API文档 Go学习笔记(五) | 使用代码片段(snippets)提高编码效率 书单 - 2018 IPFS 初体验,利用 IPFS 托管你的静态网站 记一次 PostgreSQL LIKE 索引优化,联合字段 LIKE 查询优化。 Disqus 添加有趣的 Reactions 的功能 TLS 1.3 详解 (RFC 8446解读) gRPC在Go中的使用(三)gRPC实现TLS加密通信与流模式 gRPC在Go中的使用(二)gRPC实现简单通讯 gRPC在Go中的使用(一)Protocol Buffers语法与相关使用 CentOS 安装 tshark 抓包工具 Go学习笔记(四) | win上使用VSCode搭建Go开发环境 日常 Postgres 数据库点滴记录 简单了解 PKCS 规范 美食篇 | DIY戚风蛋糕(烤箱做蛋糕) Go学习笔记(三) | 怎么写Go基准测试(性能测试) TLS1.3正式更新,为Nginx添加TLS1.3的支持 一次诡异的数据库删除 GitHub Pages自定义域名开启HTTPS 证书透明度是什么?它是怎么工作的? Go学习笔记(二) | 我对 recover 的一点误解 搭建证书透明度(certificate-transparency)日志服务之从入门到放弃 修复远程登陆 Centos 时,出现 UTF-8 Warning Go学习笔记(一) | postgres与golang点点滴滴 AWS 命令行界面(aws-cli)从安装到快速上手 数字证书分类及怎么区分各类数字证书 常用 linux 命令小结(一)文件目录操作 云服务器搭建 hexo 博客,git hooks自动更新 SSH 免密登陆, SSH Config 配置 Golang CGO Mac 交叉编译 Windows 使用 goose 让数据库迁移更加轻松 开始使用Ghost
HTTPS篇之SSL握手过程详解
2018-01-01 · via Razeen`s Blog

​接触HTTPS也有一段时间了,对整个SSL握手的过程零零碎碎的了解了一些,趁着这篇文字系统的总结一下整个SSL握手的过程,结合Wireshark工具让自己更深刻的理解SSL通信过程。

什么是握手

​像两个人沟通一样,握手是表示一个会话的开始。对于SSL/TLS来说,通过握手建立连接,交换客户端与服务器之间的信息从而生成会话秘钥(主秘钥),用来加密之后的消息。

​在TLS中有两种主要的握手类型:一种基于RSA,一种基于Diffie-Hellman。 这两种握手类型的主要区别在于主秘钥交换和认证上。

秘钥交换身份验证
RSA握手RSARSA
DH握手DHRSA/DSA

​用RSA握手还是DH握手取决于加密套件,后面我们也会带你简单了解加密套件。现在,我们用openssl查看套件时可看到

➜ openssl ciphers -v
ECDHE-RSA-AES256-GCM-SHA384 	TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 	TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
AES256-GCM-SHA384               TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(256) Mac=AEAD
AES256-SHA256                   TLSv1.2 Kx=RSA      Au=RSA  Enc=AES(256)  Mac=SHA256
...

其中kx,au就对应了秘钥交换与身份验证。

RSA握手

说了这么多终于踏入正题。

基于RSA的TLS握手整个流程如下如所示。

通过Wireshark抓包,访问https://www.razeen.me,我们可以看到

结合上面两个流程图,我们可以了解整个流程可以分解为:

  1. 客户端向服务器发送Client Hello,告诉服务器,我支持的协议版本,加密套件等信息。

  2. 服务器收到响应,选择双方都支持的协议,套件,向客户端发送Server Hello。同时服务器也将自己的证书发送到客户端(Certificate)。

  3. 客户端自己生产预主密钥,通过公钥加密预主秘钥,将加密后的预主秘钥发送给服务器 (Client Exchange)。

  4. 服务器用自己的私钥解密加密的预主密钥。

之后,客户端与服务器用相同的算法根据客户端随机数,服务器随机数,预主秘钥生产主密钥,之后的通信将都用主密钥加密解密。

下面分别带你一一了解其中细节。

Client Hello

​点开Client Hello,我们可以看到客户端向服务器发送了哪些数据。

​在一次新的握手流程中,Client Hello 消息总数第一条消息。这条消息将客户端的功能和首选项告诉服务器。通过抓包数据,通过其字段名我们也很容易理解它的含义。

Content Type

​消息的内容类型,告诉服务器,我要握手了。

Version

​协议版本(protocol version) 告诉服务器 客户端支持的最佳协议版本。

Random

​随机数,也就是流程图中的客户端随机数。包含32字节的数据,其中28字节是随机生成的(Random Bytes)。剩下的4字节包含额外的信息(GMT Unix Time),受客户端时钟影响(一般浏览器会给他们的时间添加时钟扭曲,或者简单的发送随机4字节)。在握手的时候这随机数都是独一无二的,他们在身份验证中起到举足轻重的作用(可以防止重复攻击,并确认初始数据交换的完整性)。

Session ID

​在第一连接时,会话ID(Session ID)字段是空的,这表示客户端告诉服务器 我是新会话,没有其他会话需要恢复。在后续的连接中,这个字段可以保存会话的唯一标识。服务器可以借助会话ID在自己的缓存中找到对应的会话状态。

​典型的会话ID包含32字节的随机生成的数据,这些数据本身并没有什么价值。

Cipher Suites

​密码套件块是由客户端支持的所有密码套件组成的列表,该列表是按优先级顺序排列的。

​密码套件(cipher suite)是一组选定的加密基元和其他参数,它可以精确定义如何实现安全。套件大致由以下这些属性定义。

  • 身份验证方法
  • 密钥交换方法
  • 加密算法
  • 加密密钥大小
  • 密码模式(可应用时)
  • MAC算法(可应用时)
  • PRF(只有TLS1.2一定使用,其他版本取决于各自协议)
  • 用于Finished消息的散列函数(TLS1.2)
  • verify_data结构的长度(TLS1.2)

密码套件都倾向于使用较长的描述名称,并且相当一致:它们都是由密钥交换方法、身份验证方法、密码定义以及可选的MAC或PRF算法组合而成,如下图所示:

Compression

​客户端可以提交一个或多个支持的压缩方法。默认是null,代表没有压缩。

Extensions

​扩展块由任意数量的扩展组成。这些扩展会携带额外的数据。扩展可以在不修改协议本身的条件下为TLS协议增加功能。如果你想了解更多可以参考RFC 6066,这里不多说。

Server Hello

​当服务器收到客户端的hello消息的时候,服务器会将服务器选择的参数传送回客户端。这个消息的结构与Client Hello类似,只是每个字段只包含一个选项。

​服务器不需要支持客户端支持的最佳版本。如果服务器不支持与客户端相同的版本,可以提供某个其他版本以期待客户端能够接受。

如上图所示,服务端选择使用TLS 1.2 (version),套件使用TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256。

Certificate

​从下图可以看出在服务器发送Server Hello的时候,会同时发送Certificate,Server Hello Done。

Certificate

​典型的Certificate消息用于携带X.509证书链。证书链是以ASN.1 DER编码的一系列证书,一个接一个组合而成。叶子证书必须是第一个发送,中间证书按照正确的顺序跟在叶子证书之后。根证书可以并且应该省略掉,因为在这个场景中它没有用处。

​服务器必须保证它发送的证书与选择的算法套件一致。比方说,公钥算法与套件中使用的必须匹配。除此以外,一些密钥交换算法依赖嵌入证书的特定数据,而且要求证书必须以客户端支持的算法签名。所有这些都表明服务器需要配置多个证书(每个证书可能会配备不同的证书链)。

Server Hello Done

​Sever Hello Done 消息表明服务器已经将所有预计的握手消息发送完毕。在此之后,服务器会等待客户端发送消息。

Client Key Exchange

​之后客户端向服务器发送Client Key Exchange。最后客户端与服务器互发 Change Cipher Spec,Encrypted Handshake Message。

Client Key Exchange

​Client Key Exchange 消息携带客户端为密钥交换提供的所有信息。从抓包的信息中我们可以看到,秘钥交换的主要内容是RSA Encrypted PreMaster Secret, 也就是利用证书公钥加密后的预主密钥。其中预主密钥(PreMaster Secret)是由客户端生成的48字节的随机数,RFC5426可看到其结构是这样的。

struct {
	    ProtocolVersion client_version;
        opaque random[46];
} PreMasterSecret;

Change Cipher Spec

​Change Cipher Spec 消息表明发送端已取得用以生成连接参数的足够信息,已生成加密密钥(主密钥),并且将切换到加密模式。客户端和服务器在条件成熟是会发送这个消息。

​主密钥的是由预主密钥进一步计算而成,这个过程通过一个伪随机函数(pseudorandom function, PRF)来完成,这个函数可以生产任意数量的伪随机数据。其计算过程如下。

master_secret = PRF(pre_master_secret,"master secret",ClientHello.random+ServerHello.random)

Finished(Encrypted Handshake Message)

​Encrypted Handshake Message 这是由客户端服务器之间协商的算法和密钥保护的第一个消息。它意味着握手已经完成。消息内容将加密,以便双发可以安全地交换验证整个握手完整性所需要的数据。

​这个消息包含verify_data字段,它的值是握手过程中所有消息的散列值。这些消息在连接两端都按照各自所见的顺序排列,并以协商新得到的主密钥计算散列。散列函数与PRF一致,除非协商的套件指定使用其他算法。

​客户端与服务器的计算方法一致。

verify_data = PRF(master_secret,finished_label,Hash(handshake_messages))

DH握手

​下图为TLS握手采用DH算法的流程图。与RSA最大的区别在于密钥交换与身份认证上。在RSA中是由客户端发送客户端密钥交换信息完成密钥交换,通过客户端公钥加密,服务端私钥解密完成身份认证。而在DH握手过程中则略有不同。

​下图是我访问https://razeen.me 用Wireshake抓取的数据。

我们从两个图中可以看出,在DH握手过程中,多了一步Server Key Exchange。Server Key Exchange消息的目的与Client Key Exchange目的相同,都是携带密钥交换的额外数据。而在这里它带的不再是加密的预主密钥了。

也就是说它的整个流程如下:

  1. 客户端向服务器发送Client Hello,告诉服务器,我支持的协议版本,加密套件等信息。

  2. a. 服务端收到响应,选择双方都支持的协议,套件,向客户端发送Server Hello。同时服务器也将自己的证书发送到客户端(Certificate)。

    b. 服务器利用私钥将客户端随机数,服务器随机数,服务器DH参数签名,生成服务器签名。

  3. 服务端向客户端发送服务器DH参数以及服务器签名(Server Key Exchange)。

  4. 客户端向服务端发送客户端DH参数(Client Key Exchange)。

之后,客户端利用公钥验证服务器签名,客户端与服务器各自利用服务端DH参数、客户端DH参数生成预主密钥,再通过预主密钥、客户端随机数、服务端随机数生成主密钥(会话密钥)。最后握手完成,所有的消息都通过主密钥加密。

​由于DH握手过程中大部分消息格式与RSA相同,这里不再一一说明。这里主要说明一下DH的密钥交换。

DH密钥交换

​在DH密钥交换过程中主要需要的参数有6个,其中两个(dh_p和dh_g)成为域参数,由服务器选取。协商过程中,客户端和服务器各自生成另外两个参数,相互发送其中一个参数(dh_Ys和dh_Yc)到对端,经过计算,获得预主共享密钥(PreMasterSecret),我们可以先看一下DH算法的数学基础。

+--------------------------------------------------------------------+
|                    Global Pulic Elements                           |
|                                                                    |
|       dh_p                         prime number                    |
|       dh_g                         prime number, dh_g < dh_p       |
+--------------------------------------------------------------------+
+--------------------------------------------------------------------+
|                    User A Key Generation                           |
|                                                                    |
|       Select private dh_Ys_a       sh_Ys_a < dh_p                  |
|       Calculate public dh_Yc_a     dh_Yc_a = dh_g^dh_Ys_a mod dh_p |
+--------------------------------------------------------------------+
+--------------------------------------------------------------------+
|                    User B Key Generation                           |
|                                                                    |
|       Select private dh_Ys_b       sh_Ys_b < dh_p                  |
|       Calculate public dh_Yc_b     dh_Yc_b = dh_g^dh_Ys_b mod dh_p |
+--------------------------------------------------------------------+
+--------------------------------------------------------------------+
|               Calculation of Secret Key by User A                  |
|                                                                    |
|       Secret Key premaster       premaster = dh_Yc_b^dh_Yc_a mod p |
+--------------------------------------------------------------------+
+--------------------------------------------------------------------+
|               Calculation of Secret Key by User B                  |
|                                                                    |
|       Secret Key premaster       premaster = dh_Yc_a^dh_Yc_b mod p |
+--------------------------------------------------------------------+

上面一共出现了 dh_p, dh_g, dh_Ys_a, dh_Yc_a, dh_Ys_a, dh_Yc_a, premaster 共 7 个数,其中:

  • 公开的数:dh_p, dh_g, dh_Yc_a, dh_Yc_a
  • 非公开数:dh_Ys_a, dh_Ys_b, premaster

通常情况下,dg_g 一般为 2 或 5,而 dh_p, dh_Ys_a 和 dh_Ys_b 的取值也非常大,其复杂度至少为 O(dh_p^0.5)。对于攻击者来说,已知 dh_Yc_a,dh_Ys_a 的求解非常困难,同理 dh_Ys_b 的求解也很困难,所以攻击者难以求出 premaster,所以 DH 能够保证通信双方在透明的信道中安全的交换密钥。

​在上面的介绍中你也知道,如果其中的域参数太弱,将很容易被攻破,正如2015年披露的Logjam攻击表明,512位的DH参数在使用合适的资源情况下可以被攻击者在很短的时间内成功利用。对于这些问题随后有了椭圆曲线的DH秘钥交换(ECDH),ECDH密钥交换发生在一条服务器定义的特殊椭圆曲线上,这条曲线代替了DH中的域参数,从而一定程度上提高了安全性。

总结

​到这里你理清整个握手过程了么。其实整个过程无非就是在互相交换信息,而基于RSA算法与DH算法的握手最大的区别就在于密钥交换与身份认证。前者利用客户端利用公钥加密预主密钥发送给服务端完成密钥交换,服务端利用私钥解密完成身份认证。后者利用各自发送DH参数完成密钥交换,服务器私钥签名数据,客户端公钥验签完成身份认证。

​好了就写到这里,文章中如果有错漏之处还请不吝赐教哦~

​最后,今天也是2018年的第一天,祝大家新年快乐。

参考资料

1. HTTPS 权威指南

2.SSL/TLS Perfect Forward Secrecy

3.Keyless SSL: The Nitty Gritty Technical Details

4.Announcing Keyless SSL™: All the Benefits of CloudFlare Without Having to Turn Over Your Private SSL Keys