【JavaSE-网络部分12-完结】网络原理-HTTPS协议的详细原理介绍【应用层】

🎯 你正在阅读「网络原理续命手册」系列文章 🎯


🔥 弹简特 个人主页

❄️ 个人专栏直通车:

靠热爱去书写自己,靠勇敢去书写生活!


🌟 博主简介:


在这里插入图片描述


文章目录:


上一篇 我们把 HTTP 的报文、URL、Header、Cookie、状态码分享完了。HTTP 能通信,但数据是明文传输的,容易被窃听和篡改。本篇作为 【JavaSE-网络部分12】,也是本系列最后一篇,讲 HTTPS 如何用加密和证书把 HTTP「包」进安全通道里。

一、前言

HTTPS = HTTP + TLS(老版本常叫 SSL)。HTTP 那套请求/响应格式不变,多出来的是传输前的加密、以及服务器身份的校验。

本文会从对称加密、非对称加密讲起,再说明中间人攻击为什么能得手、数字证书又怎么把公钥「验真」,最后串回 Fiddler 抓 HTTPS 的原理

二、HTTPS

1、HTTPS是什么

HTTPS 本质上给 HTTP 协议添加了加密层。如果没有加密,网络上传输的就是明文,传输的数据很容易被第三方获取,甚至篡改。

这里说的「第三方」,不一定是黑客主动攻击你,也可能是路由器、公共 WiFi、运营商中间设备等——只要数据经过它们时是明文,别人就有机会看到或改动。比如密码、Cookie、银行卡号,在 HTTP 下都可能被直接读出来。

HTTPS 做的事,简单说就是两件事:保密(别人看不懂)和校验身份(确认你连的真是这个网站的服务器,而不是冒充的)。我们平时访问网站,地址栏从 http:// 变成 https://,端口从 80 变成 443,背后走的就是这套机制。


2、加密基础:明文、密文与密钥

网络传输要想保证安全,最核心的方案就是加密

围绕着加密,会有几个关键的技术术语需要理解:

  • 明文:就是要传输的原始数据,表达原本含义。
  • 密文:把明文进行一定规则的变化,得到别人看不懂的数据。
明文 → 密文:加密
密文 → 明文:解密

加密和解密的过程中,需要用到特殊的「道具」——这种数据称之为密钥。密钥有两个作用:加密和解密。

其中,加密有两种方式:

2.1 对称加密

加密和解密用的是同一个密钥。好比一把钥匙和一把锁,你这把钥匙既能把它锁上,也能把它打开。

为啥对称加密快? 因为算法相对简单,加解密用的是同一套规则,CPU 算起来省力,所以适合加密一整段 HTTP 正文这种大块数据。HTTPS 里真正扛流量的是它,而不是非对称加密。

2.2 非对称加密

加密使用一个密钥,解密使用另一个密钥。加密和解密使用的密钥是有一定联系的,背后有复杂的数学原理。你使用密钥一来加密,此时就是使用密钥二来解密;也可以使用密钥二加密,此时就是使用密钥一来解密。

由于有两个密钥,所以在实践中通常会把其中一个密钥公开出去,这个密钥称之为公钥;另一个密钥我们自己保存好,不告诉任何人,这个密钥称之为私钥

通俗理解: 公钥像是一个「只进不出的锁」——任何人都可以拿公钥把数据锁上,但只有持有私钥的服务器能打开。所以公钥就算被全世界知道也没关系,私钥绝对不能泄露

和非对称对比: 非对称加密数学运算重,加密一大段 HTML、图片、JSON 会非常慢,所以它一般只用来保护很短的内容,比如一把对称密钥、一段校验和。


三、HTTPS的工作原理

问:学了 HTTP,学 HTTPS 要推倒重来吗?
答:不用。 报文格式、URL、Cookie、状态码……上一篇讲的,HTTPS 里全部适用。变的是:这些数据在网线里跑的时候,先被加密了。

问:那 HTTPS 到底怎么一步步做到安全的?
答:可以想成四关,一关一关过,后面每一节对应一关:

关卡解决啥结果
① 对称加密大量数据怎么加密有办法了,但密钥交不出去
② 非对称加密密钥怎么安全交给服务器有办法了,但公钥可能是假的
③ 中间人攻击公钥被掉包会怎样发现新漏洞
④ 数字证书怎么证明公钥是真的HTTPS 主干成型

下面按这个顺序讲。

1、首先最简单的是引入对称加密(第一关)

这里我们最容易懵的地方有三个:密钥谁生成的?客户端发出去时怎么用?服务器返回时又怎么用? 我们一步一步来,先别急着纠结「密钥从哪来」。

第一步:对称加密到底在干什么?

对称加密的意思很简单:加密和解密用的是同一把密钥,所以叫「对称」。

你可以先把它想成一把钥匙:

  • 上锁(加密)用这把钥匙
  • 开锁(解密)还是这把钥匙

第二步:一次完整的「问—答」,密钥怎么用?

暂时假设:客户端和服务器手里已经有同一把密钥,叫它 K。至于 K 怎么来的,下一步再说。

下面是一次正常的加密通信(注意:来回都用同一把 K):

① 客户端 → 服务器(发请求)

客户端:用 K 把「明文请求」加密 → 得到「密文请求」→ 发出去
服务器:收到密文 → 用同一把 K 解密 → 得到明文请求

② 服务器 → 客户端(回响应)

服务器:用 K 把「明文响应」加密 → 得到「密文响应」→ 发回去
客户端:收到密文 → 用同一把 K 解密 → 得到明文响应

所以别搞混了:

  • 不是客户端一把钥匙、服务器另一把钥匙
  • 而是双方共享同一把 K,谁发数据谁加密,谁收数据谁解密
  • 客户端发给服务器的用 K 加密;服务器返回给客户端的,也用 K 加密,如下图:

在这里插入图片描述

图中,路上就算有黑客截获,他看到的只是密文。没有 K,解不开——前提是黑客不知道 K 是啥


第三步:那密钥 K 到底是谁生成的?

这才是真正绕人的地方。常见就两种思路:

方式谁生成 K典型做法
A. 大家共用一把往往服务器定好,或写死在程序里所有用户装同一个 APP,里面内置 K=888888
B. 每个客户端各用一把客户端自己随机生成你这次连上来随机一个 K,跟别人的不一样

HTTPS 后面走的是 B 的思路:每次连接,客户端(和服务器协商后)会用到本次会话专用的对称密钥,不是全世界共用一把。

但不管 A 还是 B,都有一个绕不过去的坎:

不管谁生成的 K,总得让对面也知道 K 是多少,不然对方解不开密文。

  • 若是 A(共用一把):每个新客户端连上来,总得拿到这把 K(内置、下载、或服务器告诉都行)
  • 若是 B(各用各的):客户端自己生成了 K,就得告诉服务器:「我这次用 K=xxxx」

「告诉对方密钥」这一步,就是后面所有问题的起点。


第四步:方案一 —— 所有客户端共用一把 K

乍一听省事:全站用户都用 K=888888,服务器也只记这一把。

但你想:每个用户第一次打开 APP、第一次访问网站,总得 somehow 拿到这把 K 吧? 常见做法:

  • 写死在安装包里;或
  • 第一次连接时,服务器明文发给客户端

那黑客能干嘛?他不用黑服务器,只要自己写个程序,假装成普通客户端去连你的服务器。服务器分不清真假——对服务器来说都是在「发密钥给客户端」。黑客一旦也以客户端身份拿到了 K,路上所有密文他都能解开。

所以共用一把 K,等于谁都能当客户端,谁就都知道 K,不是偶然泄露,是设计上就守不住。


第五步:方案二 —— 每个客户端各自随机生成 K

这种方案相比于方案一就合理多了:A 用户随机 K1,B 用户随机 K2,互不干扰。

但是现在新的问题又来了,你看,我是让每个客户端密钥都不同了,此时我就需要想办法把密钥传输给服务器,此时你得告诉服务器,我的密钥是啥?不然你服务器不知道你客户端的密钥的话,他无法对你的数据进行解析,如下图所示:

在这里插入图片描述

客户端对服务器说,我的密钥是 888888,然后我先把这 888888 告诉你,后面我再将我的数据通过这个 888888 加密发给服务器,服务器最终通过 888888 来解密我的数据。

但是这种方案很显然是不行的,因为我们的密钥是明文传输,黑客能够拿到你的密钥信息,它可以通过密钥来解析你的数据,所以这种方案不可行。

有人可能会想:那我用另一把密钥 K2 把 888888 加密了再传行不行?

还是不行。K2 总得明文交给服务器吧?黑客截获 K2,888888 照样泄露。这就是「套娃」——不管包几层,最外面那把钥匙总得裸奔一次

所以:单靠对称加密,解决不了「第一次见面,怎么安全地把密钥交给对方」这个问题。

小结(对称加密这段):

  1. 来回通信用同一把 K,客户端发、服务器回,都靠它加解密
  2. K 要么共用,要么客户端随机生成,但总得让对面知道
  3. 「告诉密钥」这一步没法安全完成 → 只上对称加密,搞不定 HTTPS

接下来引入非对称加密,专门解决「怎么把密钥安全交给服务器」这件事。


2、引入非对称加密(第二关)

第一关我们把坑踩透了:对称加密本身没问题,卡就卡在「密钥怎么安全交给服务器」。第二关要回答的就是这件事。

这里同样最容易懵的地方也有三个:非对称到底多了什么本事?为啥不能全程用它?正常数据和传密钥为啥要分开处理? 还是一步一步来:

第一步:非对称加密,比对称多了什么?

第一关里,加密和解密用的是同一把密钥。非对称不一样——它有两把配对的密钥:公钥私钥

你可以先记住它最常用的一种用法(HTTPS 握手阶段就靠这个):

  • 公钥加密的东西,只有私钥能解开
  • 公钥可以公开,谁都能拿;私钥只有持有者自己留着

那这跟第一关的卡点有啥关系?

第一关是:客户端得告诉服务器「咱俩这次用 key=888888」,但这句话只能明文说,黑客能看见。

非对称提供了一种新可能:客户端可以用服务器的公钥,让后用公钥把这个key=888888 锁起来再发出去。 路上黑客截获了,他手里没有服务器的私钥,于是黑客就打不开这把锁——密钥就不用裸奔了。


第二步:那能不能干脆全程用非对称?

既然非对称这么厉害,能把 key 安全送过去,那 HTTP 正文、图片、JSON……也全用它加密行不行?

你先自己想想。 一张网页、一个接口返回,动不动几 KB、几 MB。非对称加密每算一次都慢,全程用它扛流量,服务器和浏览器都会算不动。

对称加密呢?第一关已经看到了——,适合大块数据。所以现实里不是「二选一」,而是各干各擅长的事

  • 大批量 HTTP 数据 → 还是对称加密(第一关第二步那套,来回用同一把 key)
  • 短短一串对称密钥 key → 交给非对称来保护(只在这一下「第一次见面」用)

这就是后面要说的混合加密。不是拍脑袋定的,是第一关的坑 + 性能,两边一起推出来的。


第三步:混合加密到底怎么组合?

第一关留下了问题:key 没法安全交给服务器。
第二步又排除了:全程非对称不现实,太慢。

那怎么办?==》针对正常传输的数据,使用的还是对称加密;但是针对对称密钥传输的时候,使用非对称加密。

说白了就是:

传什么用什么为啥
HTTP 请求/响应正文对称加密(key)快,适合大量数据——第一关第二步已经会了
对称密钥 key 本身非对称加密(公钥/私钥)只传短短一串,慢点没关系;关键是路上偷不走

注意: 不是「HTTP 用对称、密钥用非对称」两套互不相关的系统,而是先靠非对称把 key 安全送到服务器,再靠对称用这把 key 加密后面的 HTTP——前后是接在一起的。


第四步:完整走一遍——key 怎么安全交到服务器手里?

下面按时间顺序走,我们每一步都会先给一个示意图

① 服务器先生成一对密钥

  • 公钥 public1:可以给任何人
  • 私钥 private1:只有服务器自己留着
    在这里插入图片描述

② 客户端从服务器拿到公钥

公钥本来就是设计为公开的,明文传公钥没问题——就算黑客看见了,他也只是知道「锁长啥样」,没有私钥照样打不开用公钥锁起来的东西。
在这里插入图片描述

③ 客户端本地随机生成对称密钥 key

就是第一关方案二里那个思路:你这次连上来,随机一把 key,跟别的用户不一样。举例:key = 888888(此时还在客户端本地,还没上网)。
在这里插入图片描述

④ 客户端用「公钥」加密 key,发给服务器

这一步是关键——发出去的不是明文 888888,而是用公钥 public1 锁起来后的密文 Enc_public1(888888)。路上是密文
在这里插入图片描述

⑤ 服务器用「私钥」解密,拿到 key

黑客就算在中间截获了第 ④ 步的密文,他没有 private1解不开。服务器用 private1 解密 → key = 888888 到手
在这里插入图片描述

⑥ 之后就和第一关第二步一样了
上述服务器已经知道你客户端的密钥是888888了,而且这个密钥是加密传输给服务器的,你黑客不知道,所以接下来:

  • 客户端用 key(888888) 加密 HTTP 请求 → 服务器用 888888 解密
  • 服务器用 888888 加密 HTTP 响应 → 客户端用 888888 解密

在这里插入图片描述


第五步:你可能还会问的两个问题

可能有疑问:如果黑客入侵了服务器,不就拿到私钥了吗?

这个问题不太现实。因为如果黑客都有能力入侵服务器了,他直接读数据库、读文件就行,不必费劲在路上抓包。HTTPS 主要防的是「路上的黑客」,不是「服务器已经被攻破」。

那么上述看起来应该能实现了,但是有一个疑问:既然非对称加密很美好,为什么还要保留对称加密呢?

因为对称加密,加密解密的过程效率非常之高【适合数据量大的】;而非对称加密,加密解密的效率非常低【适合加密小的数据】。所以针对后续大批量的业务数据传输,使用的还是对称加密;而对于对称密钥,使用非对称加密,因为对称密钥的业务数据并不长,很适合用非对称加密来加密。

第二关小结:

  1. 第一关卡在 key 没法安全交给服务器 → 非对称用「公钥锁、私钥开」补上这一块
  2. 全程非对称不现实 → 大批量 HTTP 仍用对称
  3. 混合加密 = 非对称传 key + 对称传数据,前后接在一起

上述的过程看起来很美好,但是还有一个非常严重的漏洞,这个漏洞称之为中间人攻击。


3、中间人攻击(第三关)

第二关走下来,逻辑很顺:用 public1888888 锁起来传,路上黑客没有 private1,解不开——密钥安全送达,混合加密成立

上述的过程看起来很美好,但是还有一个非常严重的漏洞,这个漏洞称之为中间人攻击。

第三关要回答的就是:第二关到底漏了哪一块?黑客怎么又把 key 偷走了?

这里同样最容易懵的地方也有三个:攻击是在破加密算法吗?为啥客户端和服务器都察觉不到?公钥从网上拿来就能信吗? 还是一步一步来。


第一步:第二关漏了哪一块?

先别急着看图,你想一想第二关②步:客户端是怎么拿到 public1 的?

答:是从网上问服务器要来的——客户端发一句「你的公钥是啥?」,对面回什么,客户端就先信什么。

第二关只解决了:key 用公钥锁起来传,路上偷不走明文。
但还没解决:你拿到的这把「公钥」,真是服务器的吗?

客户端此刻没有能力验证「这是百度服务器的 public1,还是黑客编的 public2」。只要黑客夹在中间,把回包掉包,第二关那套加密流程照样能走通——只是你锁钥匙用的,已经不是你以为的那把锁了。

所以:中间人攻击不是把加密算法攻破了,而是攻破了「你以为在和谁说话」这件事。


第二步:中间人攻击像什么?——电影《毒战》

这个中间人攻击,和我们的一部电影叫做《毒战》非常相似,由古天乐和孙红雷扮演。

先简单说说剧情背景(没看过的同学也能听懂):

孙红雷演的是缉毒警察张静古天乐演的是毒枭李志雷——一个极其狡猾的制毒贩毒头目。警察要端掉这条线,不能光靠硬冲,得想办法盯住、参与、甚至「介入」毒贩们的那笔大交易:什么时候交货、谁跟谁接头、货和钱怎么转手,都得摸清楚。

电影里那种「交易」并不是两个人当面一手交钱一手交货那么简单。毒贩为了安全,往往层层转手:

  • 真正的买家和真正的卖家,未必直接见面
  • 中间有马仔、司机、接头人来回传话、传货
  • 每一环的人都可能跟下一环说:「放心,对面就是老熟人」

于是就会出现这种局面:买卖双方都觉得谈判还在正常推进,报价、时间、地点都对得上,气氛也像那么回事。但中间某一环被人买通、冒充、或者干脆就是警察/对手安插的人——货在中途被换了包,钱也可能进了别人的口袋;消息传到你耳朵里时,早就被过滤、篡改过了。等你反应过来,真正和你成交的,早就不一定是原来那个人了。

《毒战》里这种紧张感,很大一部分就来自:你以为在跟 A 谈,其实中间经过 B、C、D 转手,你根本看不清全貌。古天乐演的毒枭尤其擅长利用这套「中间环节」跟你绕圈子;孙红雷演的警察,也要在这些环节里抢时间、抢信息——谁控制住了「中间那一段」,谁就能占上风。

这跟中间人攻击简直是一个模子:

中间人攻击也是这个味道:

  • 客户端以为自己在和服务器谈「咱俩用哪把公钥锁 key」
  • 服务器以为自己在和客户端
  • 实际上中间站着黑客,两边瞒着对方偷偷转发——表面交易还在进行,中间却换了人、掉了包

就像《毒战》里那笔交易:买卖双方都觉得「对面就是我要找的人」,流程也在走;但关键的东西(货、钱、口令)经过中间人时,已经被掉了包。HTTPS 里掉包的是公钥——客户端以为拿到的是服务器的 public1,其实是黑客的 public2

中间人攻击是啥? 就是黑客夹在你和服务器中间,不正面硬破加密算法,而是:

  1. 假装自己是服务器,跟客户端说话
  2. 假装自己是客户端,跟服务器说话
  3. 关键信息(尤其是公钥)在中途被掉包

你以为在和银行服务器建立 HTTPS,其实第一句「公钥是啥」的回包,可能已经被黑客换成了他自己的 public2

在这里插入图片描述


第三步:动手之前——各方手里有什么?

跟第二关一样,先把角色和密钥摆清楚(下面举例仍用 888888 当对称密钥):

角色手里有什么
服务器public1 + private1(第二关①步生成的,长期用)
客户端暂时还没有 key,等会儿要随机生成 888888
黑客暂时没有,等会儿会自己生成一对 public2 + private2

在这里插入图片描述


第四步:完整走一遍——黑客怎么偷到 key?

下面跟第二关④步一样,咱们一步一步来,慢着读,对着图看。

你可以先建立一个对比框架:中间人攻击的流程,和第二关长得几乎一模一样——服务器生成密钥、客户端要公钥、用公钥锁 key、服务器用私钥解开、再用 key 加密 HTTP……
唯一致命的差别:客户端拿到的公钥,可能不是 public1,而是黑客的 public2

下面按时间顺序走。每一段先讲「发生了什么」,再点「和第二关比差在哪」。


首先:服务器生成密钥对

首先呢,由服务器生成一对公钥和私钥,公钥是 public1,私钥是 private1

这跟第二关①步完全一样——服务器开服时就生成好了,长期用;对称密钥 888888 仍是每次连接由客户端随机生成,跟 public1/private1 不是一回事。

此时还没有黑客什么事。服务器手里有:

  • public1:待会儿要发给客户端的
  • private1:待会儿用来解开「被 public1 锁住的 key」

在这里插入图片描述


然后:客户端来要公钥

然后客户端会问服务器:「咱们的公钥是啥?」然后我们的服务器就会返回公钥的内容——也就是 public1

到这一步还正常。 第二关②步走的也是这条路:公钥明文传输,路上看见 public1 没关系,因为光有公钥解不开用公钥锁起来的东西。

但隐患已经埋下了:客户端是从网上问一句、对面回一句就收下公钥的——它还没办法核实「对面真是服务器本人」
在没黑客的情况下没问题;一旦有人夹在中间,这一问一答就是掉包的机会。

在这里插入图片描述


核心:黑客掉包公钥

此时核心就出现了。

我们的黑客自己也生成了一对非对称密钥,public2private2——跟服务器生成 public1/private1 一样,谁都能造一对,数学上不费事。

差别在于:public1 是服务器身份对应的公钥,public2 是黑客身份对应的公钥
黑客拦截服务器本要发回的 public1不交给客户端,而是把 public2 塞过去,冒充服务器公钥。

从而客户端被阴了一手——他还以为这个公钥是我们服务器的公钥呢,完全并不知道被黑客给替换了
服务器那边也蒙在鼓里,它以为自己已经把 public1 发出去了。

对比第二关②步: 那时客户端拿到的是真 public1;现在拿到的是假 public2——后面所有「用公钥锁 key」的操作,锁都锁错了

在这里插入图片描述

在这里插入图片描述


客户端用错的公钥锁自己的对称密钥key

于是此时客户端就会基于这个 public2,对对称密钥 key 进行加密(举例 key = 888888),准备把对称密钥的密文传输给服务器。

从客户端视角,它觉得自己还在按第二关④步做:本地随机了 key,用「服务器公钥」锁起来,发出密文——逻辑上没毛病。

但第二关④步是 888888 + public1 → Enc_public1(888888),只有 private1 能开;
现在变成了 888888 + public2 → Enc_public2(888888),能开的是 private2——在黑客手里

加密算法没坏,是锁挂错了门

在这里插入图片描述


黑客解开密文,key 到手

此时我们的黑客就会使用自己的私钥 private2 对上述的密文进行解密,此时黑客就拿到了对称密钥 key

这一步,在第二关里本该是服务器private1 解密、拿到 888888 的地方——现在解密的人换成了黑客。

所以密钥交换这一步,黑客已经赢了:第二关⑤步想防的「路上偷 key」,防的是偷密文;但密文既然是用 public2 锁的,黑客本来就有钥匙。

在这里插入图片描述


黑客转手:用真的 public1 发给服务器

与此同时,黑客会继续使用刚才服务器的公钥 public1,对拿到的对称密钥 key 重新加密,并传给服务器。

你可能会问:黑客为啥不就此停手?
因为如果服务器拿不到 key,后面 HTTP 没法正常聊,客户端很快会发现「不对劲」。黑客得把戏演完——假装什么都没发生。

所以它用真的 public1888888 再锁一遍,发给服务器。服务器用 private1 解密,同样呢也能拿到我们的对称密钥的数据——在服务器看来,客户端就是按第二关正常流程发来的

在这里插入图片描述


在这里插入图片描述

服务器也拿到 key,握手看似成功

然后服务器拿到这个对称密钥之后,使用私钥 private1 解密——注意:这里解的是「key 的密文」,也就是黑客转发过来的 Enc_public1(888888),解出来得到 key = 888888

在这里插入图片描述

此处有一个容易混的地方: 服务器返回给客户端的「确认」,还用不用 private1
不用了。 private1 的任务到此为止——它的活儿就是解开「被 public1 锁住的 key」。
key 到手之后,双方已经有了同一把对称密钥 888888后面的确认和业务数据,都走对称加密(跟第二关⑥步一样)。

所以服务器返回的内容,可以通俗理解成:用 888888 加密的响应,意思是「好滴好滴,我已经知道你的密钥了」——客户端用 888888 解密能看懂,黑客此时手里也有 888888同样能解密、能转发
在这里插入图片描述

真实 HTTPS(TLS)里不会真的传「好滴好滴」这几个字,而是规范的握手完成报文(比如 Finished);这里是为了好懂,用口语打个比方。

这条确认经黑客转手回到客户端。客户端用 888888 解密,一看:对面确认收到了 → 更坚信密钥交换成功了

两边都以为密钥交换成功了——跟第二关⑥步表面上一样。此时:

  • 客户端有 888888
  • 服务器有 888888
  • 黑客也有 888888

客户端和服务器都察觉不到中间多了一人,因为黑客两边都在帮忙转发——key 的密文它转发,确认响应它也转发,握手流程走完了。


业务数据:加密了,但对黑客没用

此时我们客户端就知道了服务器已经收到对称密钥了,那么接下来客户端的请求都是使用对称密钥 key=888888 进行加密的。

这跟第二关⑥步、第一关第二步同一条路:HTTP 请求、响应,来回都用 888888 对称加密,量大、快。

但第二关和第三关在这里分道扬镳:

第二关⑥步第三关(这里)
黑客有没有 888888没有(没 private1,解不开 key 密文)(第④步已用 private2 偷到手)
HTTP 密文对黑客看不懂看得懂、能改

而我们的黑客手里已经有对称密钥 key 了,此时业务数据虽然是加密的,但是形同虚设——跟第一关「明文传 888888 之后的数据裸奔」效果一样,只是多绕了几圈。

在这里插入图片描述


收束:这就叫中间人攻击,漏洞在哪?

整个过程中,我们的服务器和客户端都不知道黑客的存在。上述这样的一个过程,就称之为中间人攻击

为啥双方察觉不到?
因为黑客解密后会用真的 public1 再加密转发给服务器,服务器侧握手成功;客户端侧也收到「正常」响应。表面交易还在进行——就像《毒战》里那笔货还在转,但中间早就换了包。

整个过程中的关键在于:

客户端无法区分收到的公钥是服务器的 public1,还是黑客伪造的 public2

第二关只保证了「key 被公钥锁住,路上解不开」——没保证「你手里的公钥真是服务器的」。只要公钥能掉包,混合加密整段逻辑都会被绕过去

想解决这个问题,得让客户端能证明:「这个公钥真是这个网站服务器的,不是黑客编的。」——比如引入证书,由权威第三方来盖章验真。

那么如何解决中间人攻击问题,我们就要引入一个机制,这个机制叫作校验机制。


第三关小结:

  1. 不是算法被攻破,是公钥身份没被验证
  2. 掉包的是公钥public1public2),偷走的是对称密钥 key
  3. 流程和第二关几乎一样,所以特别隐蔽——双方握手都「成功」,只有黑客能看、能改 HTTP

4、引入证书机制(第四关)

第三关把坑挖透了:公钥是从网上要来的,可能是黑客的 public2,客户端却没法分辨。

那么如何解决中间人攻击问题,我们就要引入一个机制,这个机制叫作校验机制。

第四关要回答的就是:怎么让客户端相信「这把公钥真是这个网站的」,而不是黑客编的?

这里最容易懵的地方也有三个:证书是啥?数字签名怎么防伪造?客户端验证书那三步分别在干啥? 还是一步一步来。


第一步:第三关的坑,证书要怎么填?

先回忆第三关收束时的那句话:

客户端无法区分收到的公钥是服务器的 public1,还是黑客伪造的 public2

那最直觉的想法是:让服务器自己发誓——「我发誓,我的公钥是真的!」
行吗?不行。 第三关已经演示过了:黑客冒充服务器时,也能同样发誓。自己说自己可信,等于没说。

我们需要的是:来一个客户端事先就信任的第三方,核实之后盖个章:「我查过了,www.xxx.com 用的就是这把 public1。」
这份盖了章的证明材料,就是数字证书


第二步:第三方是谁?——CA(证书颁发机构)

这个第三方,有个专门叫法:CA(Certificate Authority,证书颁发机构)。下文说的「公证机构」,指的就是它。

常见 CA 有 Let’s Encrypt、DigiCert 等。你可以把它想成办护照时的派出所、公证处——不是你自己说「我是我」,而是权威机构在材料上盖章,别人才认。

这里面的核心就是有一个第三方公证机构,它足够权威,足够说了算。那么它说公钥是正常的,此时客户端就可以相信这个公钥就是服务器给我返回回来的。

为啥必须靠 CA? 因为中间人也能伪造「自证」。客户端需要的是:只认 CA 的章,不认服务器空口白话。

在这里插入图片描述

操作系统和浏览器出厂时就内置了一批「我信任的 CA 名单」——验证书时用的 CA 公钥 public3 从这份名单来,不是临时从网上要的(这一点后面「四个问题」第 4 问会再讲)。


第三步:服务器怎么申请证书?

我们的服务器在最开始开服的时候,就需要去公证机构里面申请对应的证书。那么和我们生活中类似,你去申请一个东西,我们是需要带一些材料的——比如办护照,得带身份证或户口本

那么服务器申请证书也需要携带一些材料,比如你服务器生成的公钥是啥?服务器的域名(身份标识)。

要交的材料为啥要交注意
域名(如 www.baidu.com证明「我是这个网站」黑客拿不到别人域名的合法证书
公钥 public1证明「我以后用这把公钥跟用户通信」私钥 private1 不交出去!

CA 审核通过后,发回一张数字证书(本质就是一段有固定格式的字符串)。

两个容易混的点:

  • 对称密钥 888888:每次连接客户端随机生成,会话结束就丢,经常换
  • 服务器 public1 / private1:生成一次,配在证书里,长期用

证书干的事就是把 域名public1 绑在一起——客户端验的是「www.baidu.com 的公钥,是不是 CA 盖章确认过的那把」。

在这里插入图片描述


第四步:数字证书里到底有什么?

公证机构返回的数字证书包含下列内容:

  • 公证机构的身份标识(哪个 CA 发的)
  • 证书的有效期(啥时候过期)
  • 公钥 public1
  • 证书的所有者(服务器域名
  • 证书的 数字签名(最关键)

它其实就是一个字符串,只不过被划分为多个部分,每一部分有自己的含义。

其中最重要的部分就是数字签名。证书会不会被伪造?关键就在数字签名——它确保了证书无法被随便篡改。

在这里插入图片描述


第五步:数字签名是怎么「盖章」的?

上面看了证书结构,最后一格写着 数字签名——我们可能会卡在这里:它到底是啥?跟 public1、CA 的 public3/private3 啥关系?后面验证书时的「校验和 1、校验和 2」又从哪来?

别慌,就记一句:CA 给证书盖了一个拆不掉的章。下面用三步说完。

在这里插入图片描述


先分清两对密钥

前面第二关讲过:服务器有自己的 public1 / private1
到第四关,CA 公证机构自己也有一对密钥——咱们叫它 public3 / private3

密钥对谁的干啥
public1 / private1服务器public1 写进证书,用来锁 / 解对称密钥 888888
public3 / private3CA 公证机构CA 用 private3 给证书盖章;客户端用 public3 验章

跟服务器一样,CA 的密钥也是生成一次、长期用。区别是:

  • private3:只有 CA 自己留着,绝密,专门用来生成数字签名
  • public3写在这张网站证书里,而是预装在你电脑 / 浏览器的「受信任 CA 列表」里(第六步会讲)

所以第五步讲的「盖章」,盖的是 CA 自己的 private3;跟证书里的 public1 是两套钥匙,别混。


打个比方:合同 + 手印

签合同要签名字 + 按手印——正文大家都能看,改一个字就对不上手印。数字签名是同一思路,只不过用 SHA-256 算校验和代替手印:

步骤干啥
① 算校验和对证书正文(域名、public1、有效期……)用 SHA-256 算出一个数
② 盖章CA 用 private3 在这个校验和上加密,得到数字签名,贴在证书末尾
③ 验章客户端用内置的 public3 解开签名,看跟自己对正文算的校验和一不一致(第六步细讲)

图示:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

容易混的一点: 算校验和时只算正文,不算末尾的数字签名——签名是盖完章才贴上去的。黑客把 public1 换成自己的公钥,正文一变,校验和全变,对不上 CA 当初盖的章

CA 为啥不整份证书都用 private3 加密?因为域名、公钥本来就要公开给客户端看,只能对校验和签名,相当于在公开合同上按手印,不是把整份合同锁进保险柜。


串起来(CA 签发时)
  1. 拼好证书正文(域名 + public1 + …)
  2. 对正文做 SHA-256,得到校验和
  3. CA 用 private3 对校验和加密,得到数字签名,贴在证书末尾

在这里插入图片描述

一句话: 数字签名 = CA 用 private3 对「证书正文校验和」盖的章。证明这份正文真是 CA 审过的,不是黑客自己编的。

留给第六步: 客户端拿到证书后,自己再算一遍正文校验和(校验和 1),用电脑里内置的 public3 解开数字签名得到 CA 当初的校验和(校验和 2)——两个相等,才信证书里的 public1


第六步:从头到尾走一遍——从服务器申请到客户端验证书

这一节最容易整段糊在一起。咱们不要一上来就「校验和 1、校验和 2」,先把时间线摆清楚:

阶段什么时候发生发生几次干啥
A网站开服前一次服务器生成密钥 → 向 CA 申请 → 拿到证书并部署
B买电脑 / 装系统一次电脑里内置受信任 CA 列表(含 public3
C点 https 链接每次访问要证书 → 验签 → 通过后才走之前的第二关

下面按 A → B → C 顺序走。三把钥匙先记牢,别混:

钥匙谁的从哪来干啥
public1 / private1服务器阶段 A 生成,public1 写进证书锁 / 解对称密钥 888888
public3 / private3CApublic3 出厂内置在你电脑(阶段 B)证书上的数字签名
888888本次会话阶段 C 客户端随机生成加密 HTTP 正文

在这里插入图片描述


阶段 A:开服前(服务器 + CA,只做一次)
A-① 服务器生成 public1 和 private1

跟第二关①步一样:服务器先生成一对非对称密钥,长期用,不是每次访问都换。

  • public1:将来写进证书,给全世界看
  • private1:只有服务器留着,用来解「被 public1 锁住的 888888」

此时还没有证书,也还没有用户来访问。

在这里插入图片描述


A-② 服务器向 CA 申请证书

服务器像办护照交材料一样,带上两样东西去找 CA:

  • 域名(如 www.example.com)——证明「我是这个网站」
  • 公钥 public1——证明「我以后用这把公钥跟用户通信」

private1 不交。 私钥永远留在服务器自己手里,CA 也看不到。

CA 审核:域名是不是你的、材料齐不齐。通过后进入下一步。
在这里插入图片描述


A-③ CA 签发证书,服务器部署

CA 签发证书,就是第五步讲的那三件事,分开说:

  1. 拼证书正文:把域名、public1、有效期、CA 是谁……写在一起
  2. 算校验和:对这份正文做 SHA-256,得到一个数
  3. 盖章:CA 用自己的 private3 在这个校验和上加密,得到数字签名,贴在证书末尾

最后交给服务器的是一张数字证书 = 正文 + 数字签名

服务器把它配置到网站上。以后用户来访问,服务器出示的就是这张带 CA 章的证书,而不是空口说一句「我的公钥是 public1」。

在这里插入图片描述


阶段 B:你的电脑出厂时(只做一次)

你可能最想问的一句:客户端是不是出厂就有一个公证机构的公钥?

答:对。 更准确说:你的 Windows / macOS / Android / Chrome 内置了一份「受信任的根证书列表」,里面就有 DigiCert、Let’s Encrypt 等各大 CA 的 public3(以及对应根证书信息)。

问题答案
public3 是上网现要的吗?不是,装系统 / 装浏览器时写进本地
黑客能像第三关掉包 public1 那样掉包 public3 吗?不能(在这次连接里),因为根本没走网络
列表会变吗?系统更新可能增减;你手动安装 Fiddler 证书 = 多加一个你信任的 CA

所以:阶段 B 在你第一次访问任何 https 网站之前就完成了。 验证书时用的 public3,来自自己硬盘里的名单,不是服务器发给你的。

在这里插入图片描述


阶段 C:你点 https 链接时(每次访问)

下面假设你访问 https://www.example.com,服务器已在阶段 A 部署好证书,你的电脑已在阶段 B 内置好 CA 的 public3。


C-① 向服务器要「证书」,不要裸公钥

客户端不再问「公钥是啥」(第三关的坑),而是问:「把你的证书给我。」

证书里已经包含 public1、域名、有效期、数字签名等。

你可能还在问:要证书、返证书,路上是明文还是密文?黑客看见了会怎么想?

这两步发生在 TLS 握手前半段——888888 还没谈拢、通道还没加密,所以:

动作明文还是密文黑客能看见啥
客户端要证书明文「有个客户端在连这个站,马上要证书了」
服务器回证书明文证书全文:域名、public1、数字签名……

我们传输的内容黑客看得见么?
没错,黑客都能看见。它会不会想:「行,先让你把证书拿到手再说,后面再动手」

那么在里面黑客会获取到证书吗?
会——但让它先把真证书交到你手上,恰恰是安全的。 证书本来就是公开资料(就像营业执照挂橱窗里,不怕路人看)。第四关防的不是「证书被偷看」,而是「公钥被人掉包成假的还能骗过你」。

黑客拿到证书之后,常见几种打法:

黑客的打法结果
原样转发,不碰证书你验签通过 → 用真 public1888888 → 黑客没有 private1解不开(跟第二关「看见公钥没用」一样)
改证书里的 public1,换成 publicHACK正文变了 → 后面 C-④ 校验和对不上 → 浏览器报红
整张换成假证书,自己画一份签名没有 CA 的 private3,章是假的 → 验签不过

第三关裸公钥可以悄悄掉包;有了证书 + 验签,敢改就露馅,敢伪造就报红——所以 C-②~C-④ 才是重头戏。

在这里插入图片描述

在这里插入图片描述


客户端得到证书做以下三件事:

  1. 针对证书的各个属性,再次计算校验和,得到校验和1
  2. 客户端使用公证机构的公钥public3,对收到的数字签名进行解密,得到了校验和2。
  3. 客户端进行对比,校验和1和校验和2是否相等?

接下来一步一步说:👇

C-② 自己算校验和 1

验证书时会出现两份校验和

叫法谁算 / 从哪来
校验和 1客户端自己对证书正文再算一遍
校验和 2public3 解开数字签名,取出 CA 当初盖章时留下的那份

正常情况 校验和 1 == 校验和 2——说明是同一份正文算出来的。下面先算第一份:

客户端拆开证书,读出正文部分(域名、public1、有效期……不含数字签名),用跟 CA 签发时完全相同的 SHA-256 公式再算一遍。

「我手里这份证书正文,校验和应该是多少?」——这就是 校验和 1

若黑客把证书里的 public1 改成 publicHACK,这里算出的校验和就会变。

在这里插入图片描述


C-③ 用内置 public3 解数字签名 → 校验和 2

客户端从证书末尾取出数字签名,用阶段 B 内置在自己电脑里的 CA 公钥 public3 去解密,得到 CA 当初盖章时留下的校验和。

「发证机关认可的校验和,应该是多少?」——这就是 校验和 2

为啥是 public3 解密? 因为签名是 CA 用 private3 加出来的,只有配对的 public3 能解开——跟第二关「public1 加密、private1 解密」同一套非对称逻辑。

为啥不用问服务器要 public3? 因为 public3 在本地信任列表里,不是这次连接网上要的——这就是第四关能防住「对 CA 再来一次中间人」的原因。

在这里插入图片描述


C-④ 校验和 1 和 2 相等吗?
结果说明
校验和 1 == 校验和 2正文没被改,且真是这个 CA 签的 → 信任证书里的 public1
不相等被篡改、伪造,或 CA 不受信任 → 浏览器报红

如果相等,那么此时我就知道:服务器的公钥是:public1
在这里插入图片描述

如果校验和相等,说明证书是合法的;如果校验和不相等,说明有人对证书进行篡改了(此时很可能就是公钥被变了,那公钥就不是服务器最初的公钥)。于是客户端就会弹出提示,告诉用户当前的访问存在风险。

比如浏览器大红页「您的连接不是私密连接」——常见原因之一就是证书验不过。有人赶紧关,有人点「继续访问」——那是你愿意自担风险,哈哈哈哈。

在这里插入图片描述


C-⑤ 验过了,接下来传对称密钥

只有 C-④ 通过,客户端才相信:证书里的 public1 真是 www.example.com 的、真是 CA 盖过章的。

公钥身份确认完毕。 下面按之前顺序继续:

① 客户端随机生成本次连接的对称密钥

本地生成一把 key,比如 key = 888888。此时还在自己电脑里,还没发出去。

② 用公钥 public1 加密 key,发给服务器

用刚验过的 public1888888 锁起来 → 得到 Enc_public1(888888),发出去。
在这里插入图片描述

路上是密文——黑客就算截获,没有 private1 也解不开。
在这里插入图片描述

③ 服务器用 private1 解密,拿到 888888

private1 只有真服务器有(开服时生成,申请证书时也没交给 CA)。解开密文 → key = 888888 到手。

到这一步,客户端和服务器都握着同一把 888888 了。服务器再往回发东西——握手确认、后面的 HTTP 响应——一律用 888888 对称加密成密文,不再用 public1 / private1 了。
在这里插入图片描述

④ 双方用 888888 加密 HTTP 正文

客户端发请求:用 888888 加密 HTTP 正文 → 密文发出。
服务器收请求:用 888888 解密 → 得到明文。
服务器回响应:同样用 888888 加密 → 密文发出。
客户端收响应:用 888888 解密 → 得到明文。

黑客不知道 key,路上截到的请求、响应都是乱码,读不懂。

在这里插入图片描述

阶段 C 验证书三步,一句话串起来:

拿到证书,自己算校验和 1,用内置 public3 解签名得校验和 2,两个相等才信 public1。

第七步:四个连环问——黑客还能钻空子吗?

学完校验证书,我们可能会有一些疑问:

1)黑客能不能只改证书里的公钥?

答:改了立刻露馅。 因为黑客一旦修改了公钥,那么客户端进行证书验证的时候,就会发现自己算出来的校验和和解密签名得到的校验和不同,浏览器会提示风险。

2)那黑客改公钥的同时,把数字签名也改掉呢?

答:还是不能修改,因为数字签名的加密是公证机构的private3完成的,黑客并不知道这个密钥是啥,这个密钥始终在我们公证机构中的。那黑客即使重新计算出了校验和,他也不能计算数字签名。

3)黑客用自己之前的 private2 去「签」一个假证书呢?

答:客户端不买账。 验签时固定用内置的 CA 公钥 public3。用 public3 去解 private2 加密的东西,数学上解不开——锁和钥匙不是一对。

4)我们说客户端要使用公证机构的公钥public3来对数字签名解密,那么我们的黑客能不能对公证机构的公钥public3再来一次中间人攻击,然后把客户端拿到的public3替换成自己的公钥呢?

答:不可以,因为公证机构的公钥public3并不是通过网络传输进行获取的,而是内置在操作系统中的。

第四关小结:

  1. 第三关卡在「公钥身份未验证」→ 证书 + CA 数字签名补上
  2. 客户端只信 CA 盖过章的证书,不再盲信网上来的裸公钥
  3. 验签三步:自算校验和 1,解签得校验和 2,对比;通过才继续传对称密钥

5、HTTPS 如何保证传输安全

那稍微总结一下,我们整个 HTTPS 是如何保证数据传输安全的:

  1. 引入对称加密,对我们的业务数据进行加密。
  2. 我们引入非对称加密,对对称密钥进行加密。
  3. 黑客可以通过中间人攻击替换客户端拿到的公钥。
  4. 我们的服务器可以通过公证机构申请证书来对公钥进行验证,借助数字签名,客户端就可以确认当前的公钥是合法的。

把完整链路串成一次访问(建立 HTTPS 连接时):

  1. 客户端向服务器要证书(不是裸公钥);
  2. 用内置 CA 公钥验证书 → 通过则信任证书里的公钥;
  3. 客户端生成随机对称密钥,用证书中的公钥加密,发给服务器;
  4. 服务器用私钥解开,拿到对称密钥;
  5. 之后 HTTP 请求/响应正文,双方都用这把对称密钥加密传输。

6、Fiddler 与 HTTPS

这里边我们就可以解决以前 Fiddler 的那个问题。我们在开启 HTTPS 选项的时候,首次开启就会提示安装证书,此时安装的就是 Fiddler 的证书——本来你的系统中是没有 Fiddler 的证书的,而且 Fiddler 不是公证机构。而我们的 HTTPS 是加密传输的,那么 Fiddler 是怎么进行解密、还原处理原始数据的呢?

其实 Fiddler 抓取 HTTPS 就是靠中间人攻击实现的,只不过他这个攻击是你许可下的中间人攻击。

具体怎么干的? 你勾选解密 HTTPS 并安装 Fiddler 根证书之后:

  1. 浏览器访问 https://某网站 时,Fiddler 拦在中间
  2. Fiddler 自己当场伪造一张「某网站」的证书,用 Fiddler 自己的 CA 签名;
  3. 浏览器验签时,发现 Fiddler CA 在你系统的信任列表里 → 不报错
  4. 浏览器把对称密钥用 Fiddler 伪造证书里的公钥加密发给 Fiddler,Fiddler 解密拿到 key;
  5. Fiddler 再和真正的服务器建立 HTTPS,用真证书完成握手,在中间解密、查看、再加密转发。

如下图所示:

在这里插入图片描述

浏览器拿到 Fiddler 的证书之后,为什么没报错?因为你之前已经在系统中安装了 Fiddler 提供的证书,对系统来说,Fiddler 就像公证机构一样的,其中就包含了 Fiddler 的公钥,所以此时拿到 Fiddler 的证书,就可以使用刚才安装好的 Fiddler 公钥进行数字签名的解密和后续的校验。【其实就是你把你的工作委托给 Fiddler 来做了,你安装他的这个相当于是给他授权】

那为啥黑客不能替换这个证书呢?因为在你的系统中没有安装黑客的公钥,此时你的系统就没法把黑客使的证书视为是合法的情况。


7、SSL / TLS 与 HTTPS

上述这一系列机制有一个专门的名字来描述,叫做 SSL(Secure Sockets Layer,安全套接字层);现在主流实现是 TLS(Transport Layer Security,传输层安全),可以看作 SSL 的升级版。习惯上仍说「SSL 层」,多数时候指的就是 TLS。

HTTPS = HTTP + SSL(老版)/ TLS(新版)

和分层的关系: 严格说,TLS 工作在 TCP 之上、HTTP 之下——先由 TCP 保证数据可靠送达,再由 TLS 加密通道,最上层才跑 HTTP 报文。我们常说「HTTPS 是安全的 HTTP」,并不是 HTTP 协议本身变了,而是底下多铺了一层加密隧道。默认端口 443(HTTP 是 80)。


四、写在最后

本篇把 HTTPS 讲完了:对称加密传业务数据、非对称加密传密钥、中间人攻击、证书与数字签名验真,以及 Fiddler 抓包为何能解密——本质是你主动安装了它的证书。

回顾 【网络原理系列】 这一路,我们从协议分层入手,往下走了 TCP/UDP 怎么传、怎么保证可靠和高性能IP 怎么寻址、NAT 怎么工作;往上则用 Fiddler 抓包,把 HTTP 怎么通信、HTTPS 怎么加密 串了起来。把这些连起来看,浏览器访问网站、APP 调接口时,数据从应用层到传输层、再到网络层,大致是怎么一步步传出去的,心里就有数了。

系列到此完结。 感谢你的点赞、收藏、关注和评论区交流。下一个系列我们换主题再见,写法还是一样:多配图、多例子、把原理讲明白。

我们下一个系列见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值