tjhttp 八、《图解HTTP》 - HTTPS
知识点
- HTTPS 是什么?HTTP有哪些缺点?
- SSL、TLS为啥总是被放到一起,有什么区别?
- SSL、TLS历史背景。
- SSL的加密细节,加密算法了解。
- SSL的加密流程。
HTTP缺点
- 明文通信,内容容易被窃听。
- 无身份验证,容易受到伪装请求攻击。
- 无法验证报文完整,无法防篡改。
除了协议本身的漏洞之外,一些编程语言也可能编写出不安全的网络应用程序。
明文窃听
既然HTTP是不加密通信的,那么自然会好奇它是如何被窃听的。
所谓的窃听是因为TCP/IP模型的物理层、数据链路层、网络层这几层所需要的设备支持都不可能是个人用户所具备的东西,所以在这几个环节进行通信窃听是完全有可能的。
整个窃听的过程如下图,在网络信息通过网卡发出去的那一刻,网络包中间被“加工”的可能性就会急剧增加。这样的情况就好比一个快递从站点发出去的一刻,就有可能出现各种各样的情况。
此外加密通信并不是保证信息不被窃听,而是在窃听方拿到网络包之后无法破解明文信息内容,这样“加密”的特性就算是达到了。
常见的窃听方式比如WireShark,可以对于请求进行抓包处理。
如何防止窃听
防止明文窃听通过加密进行保护处理的方式有两种:
通信加密:
- SSL(Secure Socket Layer,安全套接层),也就是HTTPS里面的S,实现方式是在HTTP的基础上组合使用SSL通信。
- TLS(Transport Layer Security,安全层传输协议)致力于替代SSL协议,是目前的主流协议(SSL已在2015年遭到废弃)。
内容加密:
- 在传输之前对于内容明文按照某种特定规则加密,比如最常见的OAuth2。
无身份验证
无身份验证体现在下面几个方面:
- 人人都可以发送请求
- 无法确认响应的服务器是否真实。
- 无法确认发送请求的客户端是否真实。
- 无法验证发送方是否符合权限。
- 无法判定请求来源。
- 无法阻止无意义攻击(Ddos攻击)。
进行身份验证
SSL/TLS 需要通过第三方符合资质的机构进行数字认证,能获得这一机构认证本身就是十分麻烦的事情,所以通常颁发认证证书的服务器基本都可以获得加密保障,同时确认请求方的证书能有效的控制请求来源,对于客户端也能清楚请求的对方是合法安全的。
无法验证报文完整
请求在传输和响应的过程中遭到拦截并且篡改攻击的手段叫做中间人攻击(Man-in-the-Middle attack,MITM),在许多情况下这是很简单的(例如,在一个未加密的Wi-Fi 无线接入点的接受范围内的中间人攻击者,可以将自己作为一个中间人插入这个网络)。
一个中间人攻击能成功的前提条件是攻击者能将自己伪装成每一个参与会话的终端,并且不被其他终端识破。中间人攻击是一个(缺乏)相互认证的攻击。
如何防止篡改
针对中间人攻击,HTTP通常使用 MD5
和 SHA-1
等散列值校验的方法,以及用来确认文件的数字签名方法提高安全性。此外Web 网站也会提供相应的以 PGP(Pretty Good Privacy,完美隐私) 创建的数字签名及 MD5 算法生成的散列值。
但是这些手段依然无法完全保证PGP不会被篡改,HTTP本身的可靠保证过于缺乏 。
SSL协议可以验证参与通讯的一方或双方使用的证书,校验是否是由权威的受信任的数字证书认证机构颁发,并且能执行双向身份认证。
PGP 是用来证明创建文件的数字签名,MD5 是由单向函数生成的散列值。
以上内容便是HTTP本身暴露的许多缺陷导致的信息泄漏问题,也是为什么要引入SSL/TLS 协议来强化HTTP的协议的几个理由。下面我们来聊聊SSL/TLS的历史。
SSL/TLS 历史
现在我们讨论的SSL实际上是TLS,因为SSL协议本身的各种问题早已经被废弃了,目前主流的SSL实际上使用的是TLS的协议规范。
但是因为SSL被广为流传,结合历史原因,所以依然沿用这样的说法并不会产生歧义。
接着我们得明白HTTP+ 加密 + 认证 + 完整性保护=HTTPS
这个HTTPS的含义。
SSL/TLS 也是类似Cookie和Session一样,在不干扰协议本身运作的情况下对于HTTP协议本身进行保护和增强。
使用HTTPS请求之后,在浏览器输入地址的时候需要将原本的HTTP转化为HTTPS。
无论是OSI 七层模型还是TCP/IP模型,都为每个通信层的职责划分了明确的界限,HTTP是依赖TCP进行数据传输的,但是TCP为了保证单一职责和高效不会搭理HTTP的安全请求(本身也没有),他只负责数据包的收发,所以TCP是不能随便动的。而HTTP同样历史发展悠久,也难以在短时间内对于协议修订和增强。
可以看到,HTTP 是应用层协议,TCP是传输层协议,HTTP依赖TCP完成数据传输,所以 SSL/TLS 肯定是在应用层或者占据着传输层?
传输层必不可能,因为无法HTTP兼容,放到应用层这一说法其实也不完全准确。实际上SSL在TCP和HTTP的中间,类似处在两个应用的夹层里面,也就是所谓的架构难题的绝招 -- 遇事不决加一层。(因为干涉任意一层都引出更多的问题)。
中间夹层不知道为什么让我想到了《黑客帝国3》的那个车站。
明白了SSL/TLS 所处位置,我们继续了解SSL/TLS 的历史。
在许多参考资料中很多时候我们一会儿看到SSL的描述,一会儿看到TLS的描述,首先得再分清两者本身的定义。
如书中所言:
- SSL(Secure Socket Layer,安全套接层)
- TLS(Transport Layer Security,安全层传输协议)
看似是协议和“伪通信层”的东西两个不同的东西,实际上SSL是TLS的前身,或者说TLS出现的本意就是为了替换SSL而出现的“竞品”。
SSL最早出现,出道即拉胯。随着历史发展发现SSL总是存在这样那样的缺点被人诟病。TLS乘胜追击逐渐取代SSL,到了目前最新的版本是TLS1.3(已经有了一半左右的普及度)。
这里参考维基百科的介绍,大致介绍TLS/SSL 的历史。
SSL 1.0、2.0和3.0
- SSL1.0 从来没有发布过,因为存在巨大的安全漏洞和隐患。
2.0版本在1995年2月发布后,很快被发现包含许多安全和可用性缺陷。SSL 2.0 在 2011 年被 RFC "RFC (identifier)") 6176 弃用。另外SSL 2.0假设只有一个服务和一个固定域证书,这与Web服务器中广泛使用的虚拟主机功能相冲突,因此大多数网站实际上都因使用SSL而受到损害。
弃用原因:
- 消息认证使用 MD5 。 有安全意识的用户已经不再使用 MD5 [RFC6151]。
- 握手消息不受保护。
- 消息完整性和消息加密使用相同的密钥,即如果客户端和服务器协商弱加密,则会出现问题。
- 会话可以轻松终止。 中间人可以轻松插入 TCP FIN 关闭会话,对端无法确定这是否是会话的合法结束。
- SSL版本3.0.17 15 1996年发布,它由Paul Kocher与Netscape工程师Phil Karlton和Alan Freier合作制作,并由Christopher Allen和Tim Dierks设计的
Consension Development
参考实现。 - 2014年,SSL 3.0被发现容易受到影响SSL中所有块密码的POODLE攻击。RC4 是 SSL 3.0 支持的唯一非块密码,在 SSL 3.0.18 SSL 3.0 中使用时也可能被破解。
- RFC 7568 - Deprecating Secure Sockets Layer Version 3.0 (ietf.org)于 2015 年 6 月弃用SSL3。
所以SSL1.0到3.0都是比较坑的玩意儿,难怪会全面转向TLS,在2018年,谷歌、微软、苹果同时声明废弃TLS1.1、TLS1.0的使用,目前有99% 的服务器支持 TLS 1.2,基本已经完成TLS全面普及。
TLS
TLS 并不是在SSL出现问题之后才出现的,而是在SSL3.0出现之后开始修订。
- TLS 1.0 于 1999 年 1 月在 RFC 2246 - The TLS Protocol Version 1.0 (ietf.org) 中首次定义为 SSL 版本 3.0 的升级。
TLS 1.1 TLS 1.1 于 2006 年 4 月在 RFC 4346 - The Transport Layer Security (TLS) Protocol Version 1.1 (ietf.org) 中定义,重要的改进点如下:
- 增加了对密码块链接 (CBC) 攻击的保护。
- 隐式初始化向量 (IV) 被显式 IV 取代。
- 更改填充错误的处理方式。支持 IANA 参数注册。
TLS 1.2 于 2008 年 8 月在 RFC "RFC (identifier)") 5246 中定义。它基于TLS1.1 进行了下面的升级。
- 伪随机函数 (PRF) 中的
MD5–SHA-1
被SHA-256
取代,并带有使用密码套件指定 PRF 的选项。 - 完成的消息哈希中的
MD5–SHA-1
函数被SHA-256
替换,并带有使用特定于密码套件的哈希算法的选项。但是完成的消息中的哈希大小仍限制必须至少为 96 位。 - 数字签名元素中的
MD5–SHA-1
被替换为握手期间协商的单个哈希,默认为SHA-1
。 - 增强了客户端和服务器指定它们接受哪些哈希和签名算法的能力。
- 扩展了对经过身份验证的加密密码的支持,主要用于高级加密标准 (AES) 加密的伽罗瓦/计数器模式 (GCM) 和 CCM 模式。
- 伪随机函数 (PRF) 中的
TLS 1.3 于 2018 年 8 月在 RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3 (ietf.org) 中定义。它基于早期的 TLS 1.2 规范。与TLS 1.2的主要区别包括:
- 将密钥协议和身份验证算法与密码套件分离。
- 删除对弱椭圆曲线和较少使用的命名椭圆曲线的支持。
- 删除对
MD5
和SHA-224
加密哈希函数的支持。 - 即使使用以前的配置,也需要数字签名。
- 整合HKDF及半瞬时DH建议。
- 用 PSK 和门票替换恢复。
- 支持 1-RTT 握手和对 0-RTT 的初始支持。(和 QUIC 有关)。
- 通过在 (EC)DH 密钥协议期间使用临时密钥来强制实现完全的前向保密。
- 放弃对许多不安全或过时功能的支持,包括压缩、重新协商、非 AEAD 密码、非 PFS 密钥交换(其中包括静态 RSA 和静态 DH 密钥交换)、自定义 DHE 组、EC 点格式协商、更改密码规范协议、Hello 消息 UNIX 时间以及长度字段 AD 输入到 AEAD 密码。
- 禁止 SSL 或 RC4 协商以实现向后兼容性。
- 集成会话哈希的使用。
- 弃用记录层版本号并冻结该编号以提高向后兼容性。
- 将一些与安全相关的算法详细信息从附录移动到规范,并将 ClientKeyShare 降级到附录。
- 添加带有 Poly1305 消息身份验证代码的 ChaCha20 流密码。
- 添加 Ed25519 和 Ed448 数字签名算法。
- 添加 x25519 和 x448 密钥交换协议。
- 添加对发送多个 OCSP 响应的支持。
- 加密服务器后的所有握手消息。
许多材料会把TLS/SSL 的SSL放在后面,目的是考虑TLS是目前的主流,放在前面是较为合适的。
所以用现在的眼光看其实SSL早就已经被禁止了,目前主流的HTTP加密传输是基于TLS实现的。此外维基百科上有几张图介绍TLS对比SSL的优势,可以较为直观展示两者的优缺点。
算法
密码
数据完整性
网站支持
此外,根据2022年的数据显示,TLS1.3 的覆盖率和 HTTP2.0差不多,但是TLS1.2 经过这几年普及基本全方位支持。
TLS/SSL 工作机制
在了解SSL细节之前,我们需要先讲解加密方法:公开密钥加密 和 共享密钥加密。
共享/公开密钥加密
共享密钥加密加密是通信双方持有同一把钥匙加解密信息,所以这种加密方式也叫做对称密钥加密或者共享密钥加密。
共享密钥最大的问题是钥匙传输给对方的过程中有可能遭到劫持,一旦传输密钥遭到劫持,共享密钥加密的方式就相当于作废了。
中间人攻击只需要拿到密钥,双方传输加密报文的时候拦截请求数据并且伪造自己的数据,就可以同时“剽窃”双方向的敏感信息。
为了处理这个问题,需要使用公开密钥加密对于共享密钥加密对加密方式进行了改进。
改进方式很简单那就是把钥匙换成一把只能用于加密,这把钥匙可以公开对外使用,而另一把只能用于解密,只有服务端的私钥可以解开公开密钥加密的信息,外部无法通过公钥破解。
如果能在短时间内快速的进行因式分解,那么全世界所有的密码都是透明的。
有时候解密不一定是无法破解,而是破解的代价在现实上“不可能”,比如需要花费上千年的时间破解一串密码,等到破解那时候。。。。可能被破解的资源都没了。
公开密钥加密的最大特点是加密和解密的钥匙并不是同一把,两边对于密文的加解密方式不一样,所以这样的加密方式也别叫做 非对称密钥加密。
混合加密
HTTPS并不是完全使用公开密钥加密或者共享密钥加密,而是通过两种加密混合的方式进一步提升安全。
共享密钥的问题在于密钥泄露的安全性问题,而公开密钥加密因为加解密的钥匙不是同一把,需要花费更多的操作运算和验证。
HTTPS在设计的过程中基于安全和速度的考虑,最终的决定是在连接握手的过程中使用非对称密钥加密确保安全,在服务器非对称加密验证通过之后,会返回稍后需要共享对称加密的密钥信息。在握手完成之后,在确保安全的前提之下, 使用对称加密的密钥进行共享对称加密的信息交互。
需要注意这里提到的加密认证是单向认证,也就是说只会验证服务端的真实可靠性,服务端无法准确保证客户端是可靠的(但是可以确保传输是安全的)。
客户端认证只在特殊的服务上会用到,大部分服务更多使用服务端单向认证,因为多数服务就是设计给所有人都可以访问的。
数字证书加密
混合加密的方式看起来很靠谱和安全,但实际上依然存在问题,那就是无法证明公开密钥本身的真实性,为了理解这一点我们可以回顾共享密钥加密的描述图,在其中展示了攻击者在密钥传输的过程中盗取共享密钥的行为。
如果把这一行为替换为盗取公开密钥,则可以在客户端请求的时候劫持替换为攻击者自己的非对称加密密钥,之后的共享加密同样也是,可以被轻易获取。
具体的攻击过程如下:
- 服务端在数字证书认证成功之后,和客户端进行公开密钥加密认证,此时中间人截取到公开密钥,伪造出自己的公钥(同时拥有自己的私钥)以及用于共享之后传给SSL认证的客户端。
- 客户端拿到被替换的服务端公钥认证,将共享加密的密钥通过伪造的密钥加密之后,回传给服务端。
- 中间人继续劫持掉客户端请求,通过自己的私钥解密之后,用自己伪造的共享加密密钥,利用上一次服务端传递的真实公钥,加密之后传给服务端。
- 服务端拿到被加密的假的的共享密钥之后,解密获得中间人的共享加密密钥。
- 原本
在这样的攻击手段之下,为了保证客户端请求的服务器的真实性,采用第三方权威机构认证是合理的。
CA证书
为了解决这个问题,所采用的方式是通过第三方机构数字认证机构(CA,Certificate Authority),加入CA之后整个验证过程如下:
- 服务端运营请求数据认证机构申请公开密钥,数字机构验证请求者的数字认证信息,然后分配给已经签名的密钥,然后把公开密钥放入到公钥证书绑定一起返回。
- 服务器将颁发的数字认证机构的公钥证书发给客户端,使用公开密钥加密通信。这一步也叫数字认证机构传递证书。
客户端使用数字证书认证公开密钥,对于数字签名认证,认证通过可以获取两个信息
- 认证服务器的公开密钥的数字认证机构是否合法真实。
- 被认证的服务器公开密钥是否真实。
注意认证机关的公开密钥必须安全传给客户端,否则哪怕是数字认证本身还是有可能被篡改。为了规避这一个问题,许多浏览器会在安装的时候认证机构的公开密钥。
但是浏览器自带证书也有安全隐患,那就是数字认证机构遭到入侵后果不堪设想,历史上也真发生过类似事件。
EVSSL证书
证书的作用是保证服务端的公开密钥的真实性,也可以验证服务器是否真实存在。
EV SSL 证书是基于国际标准的认证指导方针颁发的证书。主要的作用是提高网站的认可度。
有时候浏览器如果带HTTPS会出现绿色打勾的字样,这样做是提醒用户网站合法性。
客户端证书
客户端证书通常会出现在安全性要求极高的特殊业务当中,同时客户端本身需要支持SSL证书的开销,但是SSL的客户端证书只能证明请求的机器是没有问题的,但是无法保证
机构信誉
作为数字认证的机构一旦出现问题后果不堪设想,在过去曾经出现过数字认机构被黑客破解的情况,其对于SSL的公信力是一次巨大打击,
OpenSSL
OpenSSL 是可以让用户自己构建一套认证机构的开源程序,但是仅能作为本地使用。
如果出现外部访问,浏览器会提示“无效证书”等内容。
HTTPS的通信步骤
下面依照SSL的的交互步骤介绍HTTPS的通信过程。
这部分内容在[[《图解HTTP》- 用户身份认证]]里面的SSL流程一致,但是对于细节做了进一步扩展。
第一次握手:确认支持SSL
客户端发送Client Hello 开始SSL通信,
HandShake
就是握手的意思,报文中指定SSL版本和加密组件(加密算法和密钥长度等)。服务器支持SSL通信,返回Server Hello
应答,报文加入SSL的版本以及加密信息。服务器的加密组件需要根据客户端支持的加密通信方式筛选。- Version: 客户端支持的TLS协议版本
- Random: 客户端生成的随机数,随后用于生成 master secret
- SessionID: 会话 ID,如果不为空,表示客户端想重用该会话
- CipherSuites: 客户端支持的加密套件列表,在 SessionID 为空时必须携带
- CompressionMethods: 客户端支持的压缩算法列表
- Extensions: 扩展内容
第二次握手:服务端证书验证
- 接收到客户端SSL版本以及加密组件信息,服务器支持SSL通信如果则返回
Server Hello
应答。 - 服务器发送
Certificate
报文,报文包含公开密钥证书,证书必须是 x.509 标准格式,包含服务端公钥、服务端域名、签发方信息、有效期等信息。 - 服务器发送
Server Hello Done
表示SSL最初的握手协商已经结束。
第三次握手:客户端确认
- 客户端按照
Client Key Exchange
回应,这个报文会在通信加密中使用Pre-mastersecret
的随机串,这个随机串第一步部分的第三个步骤已经偷偷完成加密了。 - 客户端继续发送
Change Cipher Spec
报文,告知服务器后续使用Pre-master secret
密钥加密通信(共享对称加密)。 - 客户端发送
Finished
报文。在这个报文中包含整个报文回应的校验和,客户端确认是否完成要根据服务器能否认识这一段加密报文为主。
第四次握手:服务端确认
- 服务器同样发送
Change Cipher Spec
报文,表示自己认识客户端的加密信息。 - 服务器同样发送
Finished
报文,SSL连接建立完成。
至此SSL连接建立完成,通信将会受到协商好的共享密钥加密保护,应用层开始进行通信。应用层通信,服务端进行响应。
断开连接
- 客户端主动断开链接。断开连接会发送
close_notify
的报文。之后发送TCP FIN
报文关闭通信。
注意在整个SSL四次握手的过程中,应用层发送数据时会附加一种叫做 MAC(Message Authentication Code)
的报文摘要。MAC 能够查知报文是否遭到篡改,从而保护报文的完整性。
最后是书中给的一幅图,了解整个加密过程(个人感觉画的一般,有点乱)
CBC 模式(Cipher Block Chaining)又名密码分组链接模式。此模式会把一个明文模块加密处理之后的下一个明文进行XOR运算。重叠之后对于运算结果进行加密处理。
对于第一个明文进行加密之后,
最后是IETF 关于TLS协议原文的握手步骤,看起来比较抽象,但是实际上算是最权威的交互信息了,图片展示是TLS1.2的协议原文内容:
除开最后一次的数据交互之外,服务端和客户端需要四次握手才能完成。
也就是说从TCP连接到SSL连接完成,一共需要9次握手才能最终建立一个安全连接,所以其效率可想而知。
为什么不全用HTTPS
- 纯文本通信对比的加密通信消耗更多资源
- 非敏感的HTTPS使用意义和价值不大
- 购买证书的开销和成本。CA证书购买开销不菲,但是对于现在的很多服务器来说是一笔必要开支,虽然有时候非常不合算。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。