我们今天无处不在的在使用 WEB 服务,网购、视频、新闻、在线学习、支付。互联网服务已经慢慢像水电煤气一样成为我们生活不可获取的一部分。
这 WEB 服务中 HTTP 及相关协议是一切通信的基础,整个行业都在围绕着它来使用与服务。所以 HTTP 相关问题也向 JavaScript 基础知识一样,是不可缺少的基础知识。
HTTP 发展
TCP/IP
大学计算机网络原理一开篇就介绍了网络 OSI 七层模型(还有 TCP/IP 五层模型):
应用层
会话层
表示层
传输层
网络层
数据链路层
物理层
如今人们在这七层上分别发展出了不同的协议,这些协议深入我们生活中。
层
功能
协议
应用层
文件传输,电子邮件,文件服务,虚拟终端
HTTP TFTP SNMP FTP SMTP DNS
表示层
数据格式化,代码转换,数据加密
该层被弃用
会话层
解除或建立与其他节点的联系
该层被弃用
传输层
提供端对端的接口
TCP UDP SSL/TLS
网络层
为数据包选择路由
IP ICMP RIP OSPF BGP IGMP
数据链路层
传输有地址的帧,错误检测功能
SLIP CSLIP PPP ARP RARP MTU
物理层
以二进制数据形式为物理媒体上传输数据
以太网 体制解调器 光导纤维 双绞线
可以从表中看到 TCP 属于传输层,IP 属于网络层。
TCP: 传输控制层协议,在不可靠的传输信道之上提供可靠的服务。
IP:网络地址协议,联网主机之间的路由选择和寻址功能。
我们的 HTTP 协议就是建立在这两个协议之上的,而且这两个协议一般配套使用,所以写成 TCP/IP。
TCP 三次握手
通过概念中可以看到,在不可靠的传输信道之上提供可靠地服务,原因就在这关键的三次握手????。
客户端向服务端发送一条请求,请求中包含一个随机字符序号 x(SYN)。
服务端收到请求后向客户端发送响应,将上一条报文中的随机序号 x +1,同时生成另一个随机序号 y(SYN ACK)。
客户端收到请求后将上一条报文中的 x 和 y 分别加 1,作为请求的回应,同时附带应用数据,建立了传输通信(ACK)。
通过上面三次握手????,客户端和服务端即可确认对方是要对话的人并且神志清醒可以传输数据。
TCP 报文
TCP 报文是 16 进制的字节流,其首部定义了数据传输的重要信息,好比快递上的快递单。
mac 上借助抓包工具 wireshark 即可看到完整的 TCP 报文。
HTTP 0.9 只有一行的协议
1991 年由 Tim Berners-Lee 提出,目的是支持文件传输、能够请求对超文本文档的索引搜索、格式化协商机制,以及能够把客户端引导至不同的服务器,并且构建了一个简单的原型:
客户端 / 服务器、请求 / 响应协议;
ASCII 协议,运行于 TCP/IP 链接之上;
设计用来传输超文本文档(HTML);
服务器与客户端之间的连接在每次请求之后都会关闭。
request
GET /mypage.html
response
<HTML>
这是一个非常简单的 HTML 页面
</HTML>
可以看到这个时候的 HTTP 协议简单到不能再简单了,功能也十分单一,几乎没有安全性可言。
HTTP 1.0 构建可扩展性
1991 年到 1995 年,HTML 规范和一种新型的名叫“Web 浏览器”的软件都获得了快速发展。与此同时,面向消费者的公共互联网基础设施,也日渐兴起并迅速发展起来。人们不再满足于单调的 HTML,需要多元素缤纷的互联网。
终于,1996 年 HTTP 1.0 诞生,做出了很多改变:
请求可以由于多行首部字段构成;
响应对象前面添加了一个响应状态行;
响应对象也有自己的由换行符分隔的首部字段;
响应对象不局限于超文本;
服务器与客户端之间的连接在每次请求之后都会关闭。
request
GET /mypage.html HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
response
200 OK
Date: Tue, 15 Nov 1994 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html
<HTML>
一个包含图片的页面
<IMG SRC=”/myimage.gif”>
</HTML>
在 1991-1995 年,这些新扩展并没有被引入到标准中以促进协助工作,而仅仅作为一种尝试:服务器和浏览器添加这些新扩展功能,但出现了大量的互操作问题。直到 1996 年 11 月,为了解决这些问题,一份新文档(RFC 1945)被发表出来,用以描述如何操作实践这些新扩展功能。文档 RFC 1945 定义了 HTTP/1.0,RFC 还解释了很多已经被实现的其他功能:内容编码、字符集支持、多部分类型、认证、缓存、代理行为、日期格式,等等但它是狭义的,并不是官方标准。
HTTP 1.1 互联网标准
HTTP/1.0 多种不同的实现方式在实际运用中显得有些混乱,自 1995 年开始,即 HTTP/1.0 文档发布的下一年,就开始修订 HTTP 的第一个标准化版本。在 1997 年初,HTTP1.1 标准发布,就在 HTTP/1.0 发布的几个月后。
HTTP/1.1 消除了大量歧义内容并引入了多项改进:
连接可以复用,节省了多次打开 TCP 连接加载网页文档资源的时间。
增加流水线操作,允许在第一个应答被完全发送之前就发送第二个请求,以降低通信延迟。
支持响应分块。
引入额外的缓存控制机制。
引入内容协商机制,包括语言,编码,类型等,并允许客户端和服务器之间约定以最合适的内容进行交换。
感谢 Host 头,能够使不同域名配置在同一个 IP 地址的服务器上。
一个典型的请求流程,所有请求都通过一个连接实现,看起来就像这样:
GET /en-US/docs/Glossary/Simple_header HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header
200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 20 Jul 2016 10:55:30 GMT
Etag: “547fa7e369ef56031dd3bff2ace9fc0832eb251a”
Keep-Alive: timeout=5, max=1000
Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT
Server: Apache
Transfer-Encoding: chunked
Vary: Cookie, Accept-Encoding
(content)
GET /static/img/header-background.png HTTP/1.1
Host: developer.cdn.mozilla.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header
200 OK
Age: 9578461
Cache-Control: public, max-age=315360000
Connection: keep-alive
Content-Length: 3077
Content-Type: image/png
Date: Thu, 31 Mar 2016 13:34:46 GMT
Last-Modified: Wed, 21 Oct 2015 18:27:50 GMT
Server: Apache
(image content of 3077 bytes)
这个已经是最熟悉不过的了,现在绝大多数的站点都使用的是 HTTP1.1 协议。
HTTP 2.0 改进传输性能
HTTP 2.0 的主要目标是改进传输性能,实现低延迟和高吞吐量。主版本号的增加听起来像是要做大的改进,从性能角度说的确如此。但从另一方面看,HTTP 的高层协议语义并不会因为这次版本升级而受影响。所有 HTTP 首部、值,以及它们的使用场景都不会变。
HTTP/ 2 在 HTTP/1.1 有几处基本的不同:
HTTP/ 2 是二进制协议而不是文本协议。不再可读,也不可无障碍的手动创建,改善的优化技术现在可被实施。
这是一个复用协议。并行的请求能在同一个链接中处理,移除了 HTTP/1.x 中顺序和阻塞的约束。
压缩了 headers。因为 headers 在一系列请求中常常是相似的,其移除了重复和传输重复数据的成本。
其允许服务器在客户端缓存中填充数据,通过一个叫服务器推送的机制来提前请求。
在 2015 年 5 月正式标准化后,HTTP/ 2 取得了极大的成功,在 2016 年 7 月前,8.7% 的站点已经在使用它,代表超过 68% 的请求。高流量的站点最迅速的普及,在数据传输上节省了可观的成本和支出。
后 HTTP
目前只有少部分站点支持 HTTP2,但是 HTTP 并未停止发展,会一直扩充满足互联网需求,目前 HTTP-overQUIC 协议被重命名为 HTTP3,具体了解可以看这里。
我们在 chrome 中可以看到站点请求使用了那些协议,以 www.taobao.com 为例。
HTTPS 握手
人们会用 Web 事务来处理一些很重要的事情。如果没有强有力的安全保证,人们就 无法安心地进行网络购物或使用银行业务。如果无法严格限制访问权限,公司就不 能将重要的文档放在 Web 服务器上。Web 需要一种安全的 HTTP 形式。
目前已存在一些提供认证 (基本认证和 摘要认证) 和报文完整性检查 (摘要 qop=”auth-int”) 的轻量级方法。对很多网络事务来说,这些方法都是很好用的,但对大规模的购物、银行事务,或者对访问机密数据来说,并不足够强大。这些更 为重要的事务需要将 HTTP 和数字加密技术结合起来使用,才能确保安全。
HTTP 的安全版本要高效、可移植且易于管理,不但能够适应不断变化的情况而且还应 该能满足社会和政府的各项要求。我们需要一种能够提供下列功能的 HTTP 安全技术。
服务器认证 (客户端知道它们是在与真正的而不是伪造的服务器通话)。
客户端认证 (服务器知道它们是在与真正的而不是伪造的客户端通话)。
完整性 (客户端和服务器的数据不会被修改)。
加密 (客户端和服务器的对话是私密的,无需担心被窃听)。
效率 (一个运行的足够快的算法,以便低端的客户端和服务器使用)。
普适性 (基本上所有的客户端和服务器都支持这些协议)。
管理的可扩展性 (在任何地方的任何人都可以立即进行安全通信)。
适应性 (能够支持当前最知名的安全方法)。
在社会上的可行性 (满足社会的政治文化需要)。
HTTPS 现在已经被广泛应用,甚至苹果公司要求开发者在 2017 年前全部采用「HTTPS」,这里只讨论核心的建立连接过程。
知识点扫盲
对称 / 非对称加密
对称密钥加密技术
很多数字加密算法都被称为 对称密钥(symmetric-key) 加密技术,这是因为它们在编码时使用的密钥值和解码时 一样(e=d)。我们就将其统称为密钥 k。
流行的对称密钥加密算法包括:DES、Triple-DES、RC2 和 RC4。
保持密钥的机密状态是很重要的。在很多情况下,编 / 解码算法都是众所周知的,因此密钥就是唯一保密的东西了。好的加密算法会迫使攻击者试遍每一个可能的密钥,才能破解代码。用暴力去尝试 所有的密钥值称为 枚举攻击(enumeration attack)。
但是这有一个致命的问题,发送者和接受者在对话之前一定要均持有保密秘钥(公钥),当有 N 个节点,每个节点要与其他节点进行对话的时候,就会有!N 个公钥。
公开密钥加密技术
公开密钥加密技术没有为每对主机使用单独的加密 / 解密密钥,而是使用了两个非对称密钥:一个用来对主机报文编码,另一个用来对主机报文解码。
RSA
所有公开密钥非对称加密系统所面临的共同挑战是,要确保即便有人拥有了下面所有的线索,也无法计算出保密的私有密钥:
公开密钥 (是公有的,所有人都可以获得);
一小片拦截下来的密文 (可通过对网络的嗅探获取);
一条报文及与之相关的密文 (对任意一段文本运行加密器就可以得到)。
RSA 算法 就是一个满足了所有这些条件的流行的公开密钥加密系统,它是在 MIT 发明的,后来由 RSA 数据安全公司将其商业化。即使有了公共密钥、任意一段明文、用公共密钥对明文编码之后得到的相关密文、RSA 算法自身,甚至 RSA 实现 的源代码,破解代码找到相应的私有密钥的难度仍相当于对一个极大的数进行质因数分解的困难程度,这种计算被认为是所有计算机科学中最难的问题之一。因此,如果你发现了一种能够快速地将一个极大的数字分解为质因数的方法,就不仅能够入侵瑞士银行的账户系统,而且还可以获得图灵奖了。
混合加密系统和会话密钥
任何人只要知道了其公开密钥,就可以向一台公共服务器发送安全报文,所以非对称的公开密钥加密系统是很好用的。两个节点无须为了进行安全的通信而先交换私有密钥。
但公开密钥加密算法的计算可能会很慢。实际上它混合使用了对称和非对称策略。比如,比较常见的做法是在两节点间通过便捷的公开密钥加密技术建立起安全通信,然后再用那条安全的通道产生并发送临时的随机对称密钥,通过更快的对称加密技 术对其余的数据进行加密。(SSH 和 HTTPS 都是这样的)
RSA 算法简单解释就是:
选择两个不相等的质数 p,q(比如 61 13)
算出 pq 乘积 n(322)
算出 n 的欧拉函数 φ(n)(3120)
随机选择一个整数 e,条件是 1 < e < φ(n),且 e 与 φ(n) 互质(17)
计算 e 对于 φ(n)的模反元素 d(2753)
将 n 和 e 封装成公钥(3233,17),n 和 d 封装成私钥(3233,2753)
这里最关键的是 d,因为 n 和 d 组成了私钥,一旦 d 泄漏,就等于私钥泄漏。如果 n 可以被因数分解,d 就可以算出,也就意味着私钥被破解。可是,大整数的因数分解,是一件非常困难的事情。目前,除了暴力破解,还没有发现别的有效方法。所以 RSA 算法可靠性很高。
有兴趣的可以看下阮一峰的博客:
RSA 算法原理(一)
RSA 算法原理(二)
数字签名
除了加 / 解密报文之外,还可以用加密系统对报文进行签名(sign),以说明是谁编写的报文,同时证明报文未被篡改过。这种技术被称为数字签名(digital signing)。
数字签名是附加在报文上的特殊加密校验码。数字签名通常是用 非对称公开密钥技术产生的。因为只有所有者才知道其私有密钥,所以可以将作者的私有密钥当作一种“指纹”使用。
RSA 加密系统将解码函数 D 作为签名函数使用,是因为 D 已经将私有密钥作为输入使用了。注意,解码函数只是一个函数,因此,可以将其用于任意的输入。同样,在 RSA 加密系统中,以任意顺序 应用 D 和 E 函数时,两者都会相互抵消。因此 E(D(stuff)) = stuff,就像 D(E(stuff)) = stuff 一样。
数字证书
因特网上的“ID 卡”——数字证书。数字证书 (通常被称作“certs”,有点像 certs 牌薄荷糖) 中包含了由某个受信任组织担保的用户或公司的相关信息。
数字证书中还包含一组信息,所有这些信息都是由一个官方的 证书颁发机构(CA) 以数字方式签发的。
而且,数字证书通常还包括对象的公开密钥,以及对象和所用签名算法的描述性信息。任何人都可以创建一个数字证书,但并不是所有人都能够获得受人尊敬的签发 权,从而为证书信息担保,并用其私有密钥签发证书。
X.509 v3 证书
不幸的是,数字证书没有单一的全球标准。就像不是所有印刷版 ID 卡都在同样的位 置包含了同样的信息一样,数字证书也有很多略有不同的形式。不过好消息就是现 在使用的大多数证书都以一种标准格式—— X.509 v3,来存储它们的信息。X.509 v3 证书提供了一种标准的方式,将证书信息规范至一些可解析字段中。不同类型的证 书有不同的字段值,但大部分都遵循 X.509 v3 结构。
基于 X.509 证书的签名有好几种,(其中)包括 Web 服务器证书、客户端电子邮件 证书、软件代码签名证书和证书颁发机构证书。
通过 HTTPS 建立了一个安全 Web 事务之后,现代的浏览器都会自动获取所连接服 务器的数字证书。如果服务器没有证书,安全连接就会失败。
浏览器收到证书时会对签名颁发机构进行检查。如果这个机构是个很有权威的公共签名机构,浏览器可能已经知道其公开密钥了(浏览器会预先安装很多签名颁发机构的证书)。
如果对签名颁发机构一无所知,浏览器就无法确定是否应该信任这个签名颁发机构,它通常会向用户显示一个对话框,看看他是否相信这个签名发布者。签名发布者可 能是本地的 IT 部门或软件厂商。
SSL/TLS
SSL(Secure Sockets Layer,安全套接字层)协议最初是网景公司为了保障网上交易安全而开发的,该协议通过加密来保护客户个人资料,通过认证和完整性检查来确保交易安全。为达到这个目标,SSL 协议在直接位于 TCP 上一层的应用层被实现 SSL 不会影响上层协议(如 HTTP、电子邮件、即时通讯),但能够保证上层协议的网络通信安全。
在正确使用 SSL 的情况下,第三方监听者只能推断出连接的端点、加密类型,以及发送数据的频率和大致数量,不能实际读取或修改任何数据。
SSL 2.0 是该协议第一个公开发布的版本,但由于存在很多安全缺陷很快就被 SSL3.0 取代。鉴于 SSL 协议是网景公司专有的,IETF 成立了一个小组负责标准化该协议,后来就有了 RFC 2246,即 TLS 1.0,也就是 SSL 3.0 的升级版。
TLS 1.0 自 1999 年 1 月发布后,为解决发现的安全缺陷同时扩展协议的功能,IETF 工作组先后又发布过两个新版本:2006 年 4 月发布了 TLS 1.1,2008 年 8 月发布了 TLS 1.2。从内部来看,SSL 3.0 实现与后续所有 TLS 版本很相似,很多客户端到今天还在支持 SSL 3.0 和 TLS 1.0。
简单来说网景公司的 SSL 3.0 之后更新的版本被 IETF 小组采纳并发布成为 TLS 1.0,两者差距不明显(加密算法),但是 TLS 后续会继续迭代,而 SSL 不会。
安全信道特性
数据保密性
信息加密就是把明码的输入文件用加密算法转换成加密的文件以实现数据的保密。加密的过程需要用到密钥来加密数据然后再解密。没有了密钥,就无法解开加密的数据。数据加密之后,只有密钥要用一个安全的方法传送。加密过的数据可以公开地传送。
数据完整性
加密也能保证数据的一致性。例如:消息验证码(MAC),能够校验用户提供的加密信息,接收者可以用 MAC 来校验加密数据,保证数据在传输过程中没有被篡改过。
安全验证
加密的另外一个用途是用来作为个人的标识,用户的密钥可以作为他的安全验证的标识。SSL 是利用公开密钥的加密技术(RSA)来作为用户端与服务器端在传送机密资料时的加密通讯协定。
OpenSSL 包含一个命令行工具用来完成 OpenSSL 库中的所有功能,更好的是,它可能已经安装到你的系统中了。
OpenSSL 是一个强大的安全套接字层密码库,Apache 使用它加密 HTTPS,OpenSSH 使用它加密 SSH,但是,你不应该只将其作为一个库来使用,它还是一个多用途的、跨平台的密码工具。
HTTPS 握手???? 细节
RSA 握手
RSA 握手过程:
Client Hello:客户端向服务端发送请求,请求里面包括客户端随机数(Client random)支持的协议版本(SSL/TLS)加密套件等(OpenSSL 等)。
Server Hello:服务端收到请求,保存客户端随机数(Server random),生成服务端随机数(Server random)以及选择加密方式并且将数字证书一同返回给客户端。
Client Key Exchange:客户端收到请求保存服务端随机数(Server random),验证证书并获取到服务端公钥,之后根据前两个随机数生成一个新的随机数(Premaster secret),然后用公钥将这个随机数加密发送给服务端。这时客户端已获得了 3 个随机数,将 3 个随机数使用第二步中约定的加密方法加密,生成之后传输的对话秘钥(Session key)。
Finished:服务端收到请求使用私钥解密出随机数(Premaster secret),这时服务端也获得了全部 3 个随机数,同样生成对话秘钥(Session key)。然后从此之后的内容都使用对话秘钥进行加密与解密(对称加密)。最后服务器返回一个加密的 ”Finished” 消息给客户端。
Application data:客户端用它之前生成的对话密钥(Session key)解密这条消息,验证 MAC,如果一切顺利,则建立信道并开始发送应用数据。
抓包分析 RSA 握手过程:
可以清晰地看到加密的握手过程,以及加密完成之后,应用数据抓包工具不再可以解析的出来。
DH 握手
DH 握手是在上文 RSA 基础上,修改了 Premaster secret 传输方式基础上完成的。其依赖的是 DH 密钥协商算法:
不再明文传输 Premaster secret,只需要传输 DH 参数(p, q)双方即可算出 Premaster secret。
DH 握手过程:
Client Hello:客户端向服务端发送请求,请求里面包括客户端随机数(Client random)支持的协议版本(SSL/TLS)加密套件等(OpenSSL 等)。
Server Hello:a. 服务端收到请求,保存客户端随机数(Server random),生成服务端随机数(Server random)以及选择加密方式并且将数字证书一同返回给客户端。
b. 服务端根据 Client random 和 Server random 以及 Server DH parameter 通过私钥算出签名。
Server Key Exchange:服务端向客户端发送 DH 参数以及服务端签名。
Client Key Exchange:客户端验证签名之后,向服务端发送 Client DH parameter。
Application data:服务端收到 Client DH parameter,此时双方都已有 DHparameter,通过 DH 算法算出 Premaster secret,然后将 Client random 和 Server random 以及 Premaster secret 生成 session key,接着开始加密传输数据。
Keyless SSL
2014 年,CloudFlare 推出了 Keyless SSL 方式,直至现在大规模使用。其核心在于去除本地秘钥依赖。
Yesterday we announced Keyless SSL, CloudFlare’s solution that allows sites to use CloudFlare without requiring them to give up custody of their private keys.
使用 Keyless SSL 之后的 RSA 过程和 DH 过程如下:
作为了解即可。
HTTPS 带来的问题
全站 HTTPS
简单来说可能需要注意一下的几个点:
购买证书:网站使用 HTTPS 需要申请安全证书,目前来说还是比较繁琐的,而且对小公司来说是有一些成本在。另外,一定要选正规的机构,否则你的网站以后使用主流浏览器,如 chrome 访问,会被提示大大的警告,告诉用户该证书有问题。
页面里所有资源都要改成走 https, 包括:图片、js、form 表单等等,否则浏览器就会报警。
确保用到的 CDN 节点都支持 HTTPS,如果是自建 IDC, 必须要保证全国甚至世界范围的 idc 和 cdn 节点,都得覆盖到。
所有的开发、测试环境都要做 https 的升级,确保各级环境保持同一套网络协议。
网络耗时增加,简单来说需要多几次握手,网络耗时变长,用户从 http 跳转到 https 还要一点时间。
计算耗时增加,需要更好机器性能,https 要多做一次 RSA 校验。
其中 HTTPS 带来的性能问题,可以通过优化手段来解决,可以查看案例:详解又拍云 CDN 全站 HTTPS 访问优化。
调试
当使用全站 HTTPS 之后,本地和测试环境下仍然是可以不使用 HTTPS 的。但是在某些场景下(本地前端 + 线上接口)就一定需要本地使用 HTTPS。
这里要注意的点:苹果和 Chrome 都在建议站点使用 HTTPS,但是没有要求服务端的证书级别。所以在一些不是很必要的场景,本地制作证书用于本地开发调试。
目前关于本地环境使用 HTTPS 也是有很多优秀的解决方案,这里不多做介绍,可以参考:
How to get HTTPS working on your local development environment in 5 minutes
参考
《Web 权威指南》
https://blog.csdn.net/a198810…
https://developer.mozilla.org…
https://developers.google.com…
https://zhuanlan.zhihu.com/p/…
https://blog.cloudflare.com/k…
https://razeen.me/post/ssl-ha…