解析url
URI的一般形式
- scheme: 协议名,方案名。表示资源应该使用哪种协议来访问。例如http, https, ftp、ldap、file、news等。
- authority: 表示资源所在的主机名,通常的形式是“host:port”,即主机名加端口号。有时端口号会被省略。HTTP 的默认端口号是 80,HTTPS 的默认端口号是 443。
- path:标记资源所在位置。必须以
/
开头。
- query: 表示对资源附加的额外要求。
注意file协议之后,允许省略主机名,默认是主机localhost。但对于 HTTP 或 HTTPS 这样的网络通信协议,主机名是绝对不能省略的。会导致浏览器无法找到服务器。
客户端和服务器看到的 URI 是不一样的。客户端看到的必须是完整的 URI,使用特定的协议去连接特定的主机,而服务器看到的只是报文请求行里被删除了协议名和主机名的 URI。
URI的完整形式
- User:passwd@ : 身份信息,但是不推荐这样使用,泄露重要信息 。
- #fragment :片段标识符。标识URI所定位的资源内部的一个锚点,浏览器可以跳转到它指示的位置。服务器看不到#fragment。
url编码
如果url中出现了非ASCII码以外的字符或者url中保留字符,那么它将被编码。
把字符(unicode)编码成utf-8,utf-8是用1-4个字节表示的,所以每个字节转换成16进制并在前面用百分号(%)连接,最后并把每个字节转换的结果连接起来。但是在浏览器输入框中并不会显示转以后的字符。
DNS域名解析
为什么需要域名解析呢?
在 TCP/IP 协议中使用 IP 地址来标识计算机。
- 根 DNS 服务器 :返回顶级域 DNS 服务器的 IP 地址
- 顶级域 DNS 服务器:返回权威 DNS 服务器的 IP 地址
- 权威 DNS 服务器 :返回相应主机的 IP 地址
DNS是树状的分布式查询系统。
- 首先查找浏览器中时候缓存的有该域名对应的ip地址。
- 再在本地的hosts文件中查找。
C:\WINDOWS\system32\drivers\etc\hosts
- 再去本地DNS服务器(即你家的网络服务商isp)
以上过程都没有缓存,那么它将请求根DNS服务器。
- 查询根DNS服务器,根据一级域名返回对应的顶级域名服务器的ip地址
- 查询顶级域名服务器,根据二级域名返回对应的权威域名服务器的ip地址
- 根据返回的权威服务器ip地址,然后去请求,即可查询到该域名对应的ip地址。
- 然后将其缓存在本地DNS服务器中,再将其返回给客户端。
并且这个过程也可以做负载均衡。根据服务器的压力,我们来决定返回那个服务器的ip地址。因为一个域名可以被映射出多个ip地址。
还有一个迭代解析的过程
本地DNS服务器不是自己向其他DNS服务器进行查询,而是把能解析该域名的其他DNS服务器的IP地址返回给客户端DNS程序,客户端DNS程序再继续向这些DNS服务器进行查询,直到得到查询结果为止。
TCP的三次握手
主要的目的就是保证收发双方都有接收和发送数据的能力。
在发送http请求之前,我们需要先建立一个可信的“传输通道”。这里的传输通道并不是真实存在的,他只是双方建立一种数据结构来保存双方的交互状态。
把上图的几个状态记住就行了。
- 确认 ACK :当 ACK=1 时确认号字段有效,否则无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置 1。
- 同步 SYN :在连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。
- 终止 FIN :用来释放一个连接,当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。
- 序号 seq :用于对字节流进行编号。因为应用层的传输的数据报会被分割,为了保证字节流有序。
- 确认号 ack:期望收到的下一个报文段的序号。
为什需要三次握手
《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。”
书中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。
假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。
采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”。主要目的防止server端一直等待,浪费资源。
发送HTTP请求
SSL / TLS 握手
如果发送的是https请求,那么就需要先建立TLS连接。
ECDHE握手
- 在 TCP 建立连接之后,浏览器会首先发一个“Client Hello”消息。里面有客户端的版本号、支持的密码套件,还有一个随机数(Client Random),用于后续生成会话密钥。
- 服务器收到“Client Hello”后,会返回一个“Server Hello”消息。把版本号对一下,也给出一个随机数(Server Random),然后从客户端的列表里选一个作为本次通信使用的密码套件。
- 发送数字证书给客户端(Server Certificate)。
- 发送数字证书后,服务器发送“Server Key Exchange”消息,里面是椭圆曲线的公钥(Server Params),用来实现密钥交换算法,再加上自己的私钥签名认证。
- 之后服务器发送“Server Hello Done”消息,表示消息发送完毕。
- 接下来浏览器验证数据证书的有效性。
- 验证通过后,客户端按照密码套件的要求,也生成一个椭圆曲线的公钥(Client Params),用“Client Key Exchange”消息发给服务器。
- 客户端和服务器手里都拿到了密钥交换算法的两个参数(Client Params、Server Params),使用ECDHE算法算出“Pre-Master”,其实也是一个随机数。
- 然后双方拿着 client random, server random, pre-master 生成一个主密钥。用于会话加密的。
- 客户端发一个“Change Cipher Spec”,然后再发一个“Finished”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证。
- 服务器也是同样的操作,发“Change Cipher Spec”和“Finished”消息,双方都验证加密解密 OK,握手正式结束。
RAS握手
大体的流程没有变,只是“Pre-Master”不再需要用算法生成,而是客户端直接生成随机数,然后用服务器的公钥加密,通过“Client Key Exchange”消息发给服务器。服务器再用私钥解密,这样双方也实现了共享三个随机数,就可以生成主密钥。
RSA和ECDHE算法实现握手的区别
服务器不需要通过Server key Exchange消息发送生成的公钥,pre-master是客户端直接通过RAS算法的公钥加密后生成的。
如何验证证书的有效性
浏览器需要验证证书的有效期、证书是否被 CA 吊销、证书是否是合法的 CA 机构颁发的。
验证证书的有效期。只需要查看当前时间是否在证书的有效期内就行。
验证数字证书是否被吊销了。通常有两种方式,一种是下载吊销证书列表 -CRL (Certificate Revocation Lists),第二种是在线验证方式 -OCSP (Online Certificate Status Protocol) 。
验证证书的合法性
- 首先浏览器读取证书中相关的明文信息,采用 CA 签名时相同的 Hash 函数来计算并得到信息摘要 A;
- 然后再利用对应 CA 的公钥解密签名数据,得到信息摘要 B;
- 对比信息摘要 A 和信息摘要 B,如果一致,则可以确认证书是合法的。
上面我们提到了利用CA的公钥来解密签名,那浏览器是如何获取到CA公钥的呢?
通常,当你部署 HTTP 服务器的时候,除了部署当前的数字证书之外,还需要部署 CA 机构的数字证书,CA 机构的数字证书包括了 CA 的公钥,以及 CA 机构的一些基础信息。
有了CA的公钥,那我们怎么知道这个共要是安全的呢?不是恶意的CA机构颁发的呢?
这里就是无限套娃的验证了。直到查找到根CA证书(目前通过 WebTrust 认证的根 CA 有 Comodo、geotrust、rapidssl、symantec、thawte、digicert 等),然后比对操作系统中是否内置的有这个根CA,如果有,浏览器就会认为使用者的证书是合法的。