VaporSpace 首页

https原理,为啥ssl协议这么设计

2023-05-20 08:50

摘要和非对称加密

在了解的安全协议之前,需要先讲两个前置概念,也是后续理解的关键。

摘要: 摘要算法是对数据的有损压缩,是单向不可逆的,就是一种哈希运算结果。可以用来做数据比较,当两份数据的摘要结果是一致的,说明两份数据也是一致的。常用的摘要算法:MD5、SHA-1等。

非对称加密:

如何设计一个安全通信方案?

下面将会一步一步设计一个安全的通讯协议,每一个阶段会列出解决和遗留的问题。

  1. 明文通讯

    • 安全问题
  2. 双方对称加密通讯,双方线下存储密钥

    • 信息可以加密
    • 随着通讯对象增加,需要存储的密钥会越来越多
    • 每增加一个对象,都必须线下去交换一次密钥,非常麻烦
  3. 非对称加密通讯,明文将公钥发出,双方交换公钥

    • 公钥可以明文发送,不需要线下分配密钥,也不需要事先存好密钥
    • 每次通讯都用非对称加密,计算量大
    • 公钥对所有人开放,即意味着无法确定信息的准确来源,是谁发过来的
    • 公钥交换过程是明文,可能会被中间人劫持修改(中间人在传输过程中修改成自己的公钥,即可监听对话)
  4. 非对称加密传送密钥,然后再通过对称加密通讯。即生成一个密钥 A,通过公钥加密传输给对方,并告诉对方之后的通话要经过密钥 A 来加密。

    • 解决非对称加密计算量大问题
    • 仍无法确认信息来源
    • 中间人劫持公钥
  5. 到这里,如果不解决中间人劫持的问题,就无法进行下去了。所以我们需要引入一个可靠的第三者,我们称之为授信机构,机构生成一对非对称密钥,每个需要通讯的人都去此机构领取公钥,并且机构会对申请人的个人信息进行认证和签名(私钥加密)。此后,所有人通讯前,都用机构公钥去解密对方的机构签名,这样就能确认对方是谁了。所以此机构相当于是一个互联网的身份登记机构。

    • 可以确认信息来源,同时杜绝了中间人劫持

由于存在授信机构,只需要申请一次公钥(证书),且只需要存储一个公钥,即可跟所有人进行加密通讯。而这个授信机构也就是现在的 CA机构(证书授权中心),机构签名和公钥则构成数字证书,每个浏览器都会内置 CA机构 的根证书。

下面会讲述数字证书和安全协议的更多细节。

数字证书

CA 机构(证书授权中心)会生成一个根证书(带有公钥)和私钥,根证书会内置在所有浏览器里,私钥则用于服务器证书的签名。所以只有经过机构认证的服务器,才能进行加密通信。

CA 机构向有资质的服务器发放服务器证书,不同安全等级的证书需要不同的申请资料,如申请电子商务服务器证书需要营业证明。

下图是证书的内容:(下面颁发者的签名只是个比喻,实际应该是一串加密字符)

来自《http权威指南》

一个受根证书信任的证书 A,可以对另一个新建的证书 B 进行签名,这样根证书也会信任证书 B,这是一个证书信任链条。所以并非只有根证书才能给其他证书签名。

来自《HTTPS权威指南》

B站的证书路径

当客户端收到服务端的证书,会通过证书的发布机构(Issuer)递归向上反查到其根证书,从而保证证书信任链的有效。

SSL 和 TLS 安全协议

两者都是加密层的协议,TLS 是 SSL 的更新版本,修复了一些安全漏洞。因为两者很相似,所以下面以 SSL 为代表讲解安全层是如何建立的。

来自《http权威指南》

建立 SSL 连接

  1. 客户端发送支持的安全协议、加密方法、随机数a(客户端生成)等;
  2. 服务器返回确认的安全协议、加密方法,以及随机数b(服务端生成)和证书;
  3. 客户端验证证书,首先查看证书的颁发机构、期限以及域名等,保证了证书本身信息合法后,通过根证书的公钥验明证书上的签名。验签后,取出证书公钥,对此次发送的信息进行加密。这次会发送给服务端随机数c(客户端生成),并通知服务端之后的通信将用密钥加密;
  4. 服务端最后一次返回,通知客户端已知后续内容要加密,并且将之前发送内容生成hash值一并返回给客户端,以供客户端校验;
  5. 通过前面几次握手,共产生随机数a、b、c,且同时存在于两端,两端用这三个随机数生成密钥,通过约定好的加密算法加密之后通讯的内容;

SSL握手.png

如何确定明文证书不会被劫持?

在证书生成的时候,除了有基本信息外,还有颁发机构的私钥签名,这个签名是通过对整个证书的内容(包括服务器公钥)摘要加密生成的。

所以如果有中间人想要调包证书,那浏览器会找不到解签的公钥而判定此证书是非法证书。

如果想把证书公钥换成中间人自己的,也不行,因为客户端也会对证书内容进行摘要,然后再跟证书解签出来的摘要进行对比,这样就能知道证书内容是否被修改过。

每次会话都需要握手吗?

SSL 的多次握手需要一定时间,所以当连接断开一段时间内,双端都会保留一个 Session Id 用于快速重新握手。当重连时,客户端依然进行第一次握手,但会带上之前连接保留下来的 Session Id;服务端在上此连接时,将 Session Id 作为 key,密钥作为 value 存储起来,拿到客户端发来的 Session Id 就可以验证是否存在过,存在则告知客户端恢复连接。

但 Session Id 存在两个问题,一是服务端存储大量的 Session Id 和通信密钥,内存占用高;二是如果服务器是集群,则需要一个共享数据库去存储 Session Id,增加读写性能压力。

为了解决这两个问题,后来协议新增了一个 Session Ticket。顾名思义,它是服务端给客户端发送的一个票据,通过这个票据可以恢复会话,不再需要存储于客户端。具体操作是,当完成完整握手后,服务端会将此次的通讯密钥加密成 Ticket 发送给客户端(Ticket 只有服务器能解密),并且还需要告知客户端 Ticket 的时效,到时必须删除。当客户端之后重连时,将 Ticket 带给服务端,服务端解密出上次的通讯密钥,即可恢复加密通信。

https 代理

在写这篇文章的同时,我实现了一个简单的代理抓包工具,感兴趣的可以看下 https://github.com/Mess663/v-proxy

参考:

https://imququ.com/post/web-proxy.html
https://awesome-programming-books.github.io/http/HTTP权威指南.pdf https://github.com/anzhihe/Free-Web-Books/blob/master/book/HTTPS权威指南.pdf https://www.lyyyuna.com/2018/03/16/http-proxy-https/ https://www.ruanyifeng.com/blog/2014/02/ssl_tls.html https://www.bookstack.cn/read/https-mitm-proxy-handbook/doc-Chapter3.md https://segmentfault.com/a/1190000024523772