HTTPS请求全过程

从浏览器输入域名www.baidu.com,敲击回车开始,都经历了一些什么?

DNS解析

当我们在浏览器中输入网址并且按下回车,浏览器会在浏览器DNS缓存,本地DNS缓存,和host文件中寻找对应的记录,如果没有获取到,则会基于UDP协议请求默认DNS服务器( Local Name Server )来获取对应的IP。
默认DNS服务器会首先查询自己的缓存,如没有,再从根域名服务器开始不断迭代查询,直到获取到IP地址返回给客户机,同时在缓存中保存一份以备下次查询。具体过程如下图所示:
迭代查询
HTTPS请求全过程 - 图1

建立TCP连接

通过第一步得到目标IP地址后,客户端进程User-Agent,即浏览器会以一个随机端口([1024-65535])向监听443/80端口的服务器进程(httpd/nginx)发起TCP连接请求,开始三次握手建立连接。过程如下图(client_isn/server_isn为随机数):
HTTPS请求全过程 - 图2四次挥手:
HTTPS请求全过程 - 图3

HTTPS单双向验证

https是在TCP协议与http之间加了一个控制安全传输的SSL协议。
HTTPS请求全过程 - 图4客户端收到证书后,检查证书是否合法,主要检查下面4点:

  1. 检查证书是否过期
  2. 检查证书是否已经被吊销。
    有CRL和OCSP两种检查方法。CRL即证书吊销列表,证书的属性里面会有一个CRL分发点属性,如下图所示(CSDN的证书),这个属性会包含了一个url地址,证书的签发机构会将被吊销的证书列表展现在这个url地址中;OCSP是在线证书状态检查协议,客户端直接向证书签发机构发起查询请求以确认该证书是否有效。
  3. 证书是否可信。
    客户端会有一个信任库,里面保存了该客户端信任的CA(证书签发机构)的证书,如果收到的证书签发机构不在信任库中,则客户端会提示用户证书不可信。
    若客户端是浏览器,各个浏览器都会内置一些可信任的证书签发机构列表,在浏览器的设置中可以看到。
    如果不在信任表中,则浏览器会出现警告页面,提示你不安全。
    若客户端是程序,例如Java中,需要程序配置信任库文件,以判断证书是否可信,如果没设置,则默认使用jdk自带的证书库(jre\lib\security\cacerts,默认密码changeit)。如果证书或签发机构的证书不在信任库中,则认为不安全,程序会报错。(你可以在程序中设置信任所有证书,不过这样并不安全)。
  4. 检查收到的证书中的域名与请求的域名是否一致。
    若客户端是程序,这一项可配置不检查。若为浏览器,则会出现警告,用户也可以跳过。
  5. 打包http传递数据开始通信
    经过层层打包发送过去
    再层层解包给niginx

用到3个随机数组合是为了让随机数更接近真随机,防止被破解。
如果服务器在配置中加入了对客户端的验证,则过程如下。
双向验证(由服务器决定)
HTTPS请求全过程 - 图5客户端证书验证消息(CertificateVerify message):客户端将之前所有收到的和发送的消息组合起来,并用hash算法得到一个hash值,然后用客户端密钥库的私钥对这个hash进行签名,这个签名就是CertificateVerify message
服务器收到客户端证书后:
a)确认这个证书是否在自己的信任库中(当然也会校验是否过期等信息),如果验证不通过则会拒绝连接;
b)用客户端证书中的公钥去验证收到的证书验证消息中的签名。这一步的作用是为了确认证书确实是客户端的。
所以,在双向验证中,客户端需要用到密钥库,保存自己的私钥和证书,并且证书需要提前发给服务器,由服务器放到它的信任库中。

客户端发起HTTP请求

加密信道建立完成后就可以开始传输数据了。HTTP可以发起请求。
使用的 http方法是 GET,请求的 URL是 /,协议是 HTTP/1.1。
发起的 http请求报文头部参数:

Accept 就是告诉服务器端,我接受那些 MIME类型 Accept-Encoding 这个看起来是接受那些压缩方式的文件 Accept-Lanague 告诉服务器能够发送哪些语言 Connection 告诉服务器支持 keep-alive特性 Cookie 每次请求时都会携带上 Cookie以方便服务器端识别是否是同一个客户端 Host 用来标识请求服务器上的那个虚拟主机,比如 Nginx里面可以定义很多个虚拟主机,这里就是用来标识要访问那个虚拟主机。 User-Agent 用户代理,一般情况是浏览器,也有其他类型,如: wget curl 搜索引擎的蜘蛛等

条件请求首部:

If-Modified-Since 是浏览器向服务器端询问某个资源文件如果自从什么时间修改过,那么重新发给我,这样就保证服务器端资源文件更新时,浏览器再次去请求,而不是使用缓存中的文件

安全请求首部:

Authorization: 客户端提供给服务器的认证信息;

服务器响应HTTP请求

nginx读取配置文件
WEB程序,即 nginx等,在收到请求( GET/HTTP/1.1)时,会读取 http请求里面的头部信息;
根据 Host来匹配自己的所有虚拟主机的配置文件的 server_name,看看有没有匹配到;
有匹配的话就查看该虚拟主机的配置,找到配置(root/var/www/html/),这个就表示所有的网页文件都在这个目录下,也就是网站的根目录;
如果直接输入www.baidu.com,会默认进入首页,首页的配置从这个配置项获取( index index.html index.htm index.php);
如果在上面的配置没有找到,就将请求交给 uwsgi来处理, uwsgi经过后端逻辑的处理返回 json数据,或者是渲染好的 html页面。

浏览器渲染页面

浏览器拿到 html页面或者 json数据,开始解析 html代码,加载 js/css/image等静态资源,请求服务器下载静态文件,这个时候就利用了 keep-alive特性,即建立一次 HTTP连接,可以请求多个资源。