1、Http协议
1.1 概念
Http协议(HyperText Transfer Protocol,超文本传输协议)是TCP/IP协议组之一,属于OSI七层网络模型(应表会传网数物)的应用层,指定了客户端可能发送给服务器什么样的请求以及得到什么样的响应,以 ASCII 码传输。 一次Http连接是一次无状态的灵活连接。 一次:Http连接是一次性的,每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求再重新建立连接。避免服务器的连接处于等待状态,及时释放能够提高服务器的执行效率。 无状态:Http协议是一种无状态协议,即服务器不保留与客户端连接时的任何状态。减轻了服务器存储负担,从而保持较快的响应速度。 灵活:Http协议是一种面向对象的协议。灵活在于允许传送任意类型的数据对象,正在传输的类型由Content-Type加以标记,通过数据类型和长度来标识所传送的数据内容和大小,并允许对数据进行压缩传送。
Http请求报文格式由四部分组成(请求行、请求头、空行、请求体): 1)请求行:请求行由请求方法字段、URL字段和Http协议版本字段3个字段组成,它们用空格分隔。以“\r\n”结尾。例如,GET /index.html HTTP/1.1。HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。 2)请求头:请求头由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。以“\r\n”结尾。请求头通知服务器有关于客户端请求的信息,典型的请求头有: User-Agent:产生请求的浏览器版本信息。 Accept:客户端可识别的内容类型列表,类型用MIME表示。 Accept-Charset:客户端接受什么字符集的文本内容。常用的如UTF-8,GBK,iso-8859-1等。 Cookie:非常重要的请求头,常用来表示请求者的身份。比如有些会话信息(SesssionId)会存在Cookie中。 Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。 Refer:告诉服务器,当前请求从哪里来,如果是从超链接来的,就存放该超链接页面的地址,否则为null,防盗链,做统计工作。 Connection:keep-alive(可复用)。在http1.1,请求和响应头中都有可能出现一个connection的头,此header的含义是当client和server通信时对于长链接如何进行处理。在http1.1中,client和server都是默认对方支持长链接的, 如果client使用http1.1协议,但又不希望使用长链接,则需要在header中指明connection的值为close;如果server方也不想支持长链接,则在response中也需要明确说明connection的值为close。不论request还是response的header中包含了值为close的connection,都表明当前正在使用的tcp链接在当天请求处理完毕后会被断掉。以后client再进行新的请求时就必须创建新的tcp链接了。keep-alive在很多情况下能够重用连接,减少资源消耗,缩短响应时间,所以在HTTP1.1中缺省支持keepalive。 3)空行:最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。以“\r\n”结尾。分割请求头和请求体。 4)请求体:封装POST请求的请求参数。POST方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。
Http响应报文格式由四部分组成(响应行、响应头、空行、响应体): 1)响应行:由协议/版本、响应状态码、状态码描述组成,以空格分割,以“\r\n”结尾。例如:HTTP/1.1 200 OK。 响应状态码:服务器告诉浏览器本次响应的状态,都是三位数字 1xx:Informational(信息性状态码),接受的请求正在处理。服务器接收客户端消息,但没有接收完,等待一段时间,发送1xx 2xx:Success(成功状态码),请求正常处理完毕。成功,如:200 3xx:Redirection(重定向状态码),需要进行附加操作完成请求。重定向,如:302(重定向)、304(访问浏览器本地缓存),每张图片都是一次访问 4xx:ClientError(客户端错误状态码),服务器无法处理该请求。客户端错误,如:404(请求路径没有对应的资源)、405(请求方式没有对应的处理方法doGet等) 5xx:ServerError(服务器错误状态码),服务器处理请求出错。服务器端错误,如:500(服务器内部异常) 2)响应头:键值对组成,一行一对,关键字和值用英文冒号“:”分隔,以“\r\n”结尾。 Server:服务器所使用的Web服务器名称。攻击者可以通过查看该头信息,来探测Web服务器名称。所以一般服务器端会对该头信息进行修改。 Server: Apache/2.4.6 (CentOS) Set-Cookie:向客户端设置Cookie。与Cookie请求头相互对应。Set-Cookie头是服务器向客户端设置Cookie,Cookie头是客户端向服务器传客户端已经保存的Cookie信息。 Location:服务器通过该头信息告诉浏览器去访问那个页面,浏览器接收到这样的响应信息后,通常会立刻访问Location头所指向的页面。这个头通常配合302重定向状态码使用。 Refresh:服务器通过Refresh头信息让浏览器定时刷新。比如下面这个头信息定时三秒后,刷新到百度页面:Refresh: 3;url=“http://www.baidu.com” Cache-Control:指定客户端对页面的缓存策略。比如下面的头信息表示指定客户端不缓存该页面内容:Cache-Control: no-cache Content-Type:text/html;chrset=UTF-8,服务器告诉客户端本次响应体数据格式以及编码格式,MIME类型 Content-disposition:服务器告诉客户端以何种格式打开响应体数据 in-line:默认值,在当前页面内打开 attachment;filename-xxx:以附件形式打开响应体,文件下载 3)空行:同请求空行,以“\r\n”结尾。分割响应头和响应体。 4)响应体:响应的数据。JSON。
1.2 发展
1)HTTP/0.9版本(1991):最早定稿的HTTP版本,版本的内容非常地简单。只有一个命令GET。对应到现在的GET请求和POST请求,这些叫做HTTP的命令或者方法。没有HEADER等描述数据的信息,服务器发送完内容之后,就关闭TCP连接。需要注意,这里的TCP连接和http请求是不一样的。http请求和TCP连接不是一个概念。一个http请求通过TCP连接发送,而一个TCP连接里面可以发送很多个http请求(HTTP/0.9不能这么做,但是HTTP/1.1可以这么做,而且在HTTP/2这方面会更大程度地优化,来提高HTTP协议传输的效率以及服务器的性能)。所以一个TCP连接对应的是多个http请求,一个http请求肯定是在某一个TCP连接里面进行发送的。
2)HTTP/1.0版本(1996):与HTTP/1.1类似,在HTTP/0.9版本基础上进行了改进。增加了很多命令,如:POST、PUT、HEADER命令。增加状态码和header相关的内容。增加多字符集支持、多部分发送、权限、缓存等相关的内容,有利于更好地使用http请求去实现WEB服务。
3)HTTP/1.1版本(1999):在HTTP/1.0的基础上增加了一些功能来优化网络连接的过程。 支持持久连接,在HTTP/1.0版本里面,http请求的发送依赖于客户端和服务器端之间的TCP连接,创建TCP连接后,等服务器端返回完数据之后,TCP连接将关闭。创建和关闭TCP连接的成本是相对较高。持久连接可以不关闭,之后新的http请求就可以一直在这个连接里面进行数据发送,性能和效率提升很多,HTTP/1.1已经实现了这个功能。 增加了pipeline。可以在同一个TCP连接里面发送多个http请求。但在HTTP/1.1里面,虽然是可以在同一个TCP连接里面发送多个http请求,但是服务器端对于进来的请求,是要按照顺序进行数据返回的。因此,如果前一个请求等待时间非常长,而后一个请求处理得比较快。这个时候后一个请求不能先发送,而是要等第一个请求数据全部发送完成之后,才能进行发送,即是串行的。等待的这部分时间就体现出了与并行传输性能之间的差距。而这个在HTTP/2里面得到了优化。 增加了HTTP的头host和其他一些命令。其中比较重要的就是host,有了host之后就可以在同一台服务器(物理服务器)上同时跑多个web服务。比如说一个Node.js的web服务,一个Java的web服务。通过host这个字段来表示两个服务都是请求到同一个物理服务器上,但是我要请求的是里面哪一个软件服务,Node.js还是Java?这就是通过host来进行判断的。这个host头增加的好处就是,在同一个物理服务器或者同一个集群里面可以部署很多不同的web服务来,提高了物理服务器的使用效率。
4)HTTP/2版本(2015):虽然现在还没有普及,但是毫无疑问是未来的趋势。 所有数据都是以二进制进行传输的。在HTTP/1.1里面大部分的数据传输是通过字符串,所以数据的分片方式是不太一样的。在HTTP/2里面所有的数据都是以帧进行传输的。正是因为有了这个好处,同一个连接里面发送多个请求时,服务器端不再需要按照顺序来返回处理后的数据了。而是可以在返回第一个请求里面数据的时候,同时返回第二个请求里面的数据。这样的并行传输能够更大限度地提高web应用的传输效率。新增头信息压缩以及推送等功能,提高了传输效率。HTTP/2其实主要就是改善了HTTP/1.1里面造成性能低下的一些问题。 ·头信息的压缩。在HTTP/1.1里面每一次发送请求和返回请求,很多http头都是必须要进行完整的发送和返回的,但是这一部分头信息里面有很多的内容比如说:Headers字段、Content-Type、accept等字段是以字符串的形式保存的。所以占用较大的带宽量。所以HTTP/2里面对头信息进行了压缩,可以有效地减少带宽使用。 ·分帧传输。采用分帧传输的数据传输方式。在分帧的方式中,每一帧都有上下帧的联系,意思是传输当一个http请求的信息时,并不一定要按照连续的方式进行发送,而是可以把信息分成不同的帧一起发送。如果中间的帧先到服务器,没有关系,等服务器把请求数据全部接收完之后,会根据帧信息里包含的先后顺序,把帧进行组合,得到一个真正的数据。得益于分帧传输与信道复用功能,使得在HTTP/2中,同一个连接可以并发地发送多个不同的请求。 ·推送的功能。指的是HTTP/2之前,只能由客户端发送数据,服务器端返回数据。客户端是主动方,服务器端永远是被动方。在HTTP/2里面有了”推送”的概念,也就是说服务器端可以主动向客户端发起一些数据传输。举个例子:我们知道一个web页面加载时会要求一些html、css、js等文件,css和js文件是以链接的形式在html文本里面显示的,只有通过浏览器解析了html里面的内容之后,才能根据链接里面包含的URL地址去请求对应的css和js文件。在HTTP/2之前,这个传输过程会包含顺序问题,需要先请求到html的文件,通过浏览器运行解析这个html文件之后,才能去发送css的请求和js的请求。HTTP/2中有了推送功能之后,在请求html的同时,服务器端可以主动把html里面所引用到的css和js文件推送到客户端,这样html、css和js的发送就是并行的而不是串行的,整体的传输效率和性能就提高了不少。
2、Https协议
2.1 由来
HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):一般理解为HTTP+SSL(Secure Socket Layer,安全套接字层)/TLS(Transport Layer Security,传输层安全),通过 SSL证书来验证服务器的身份,并为浏览器和服务器之间的通信进行加密,提供加密处理数据、验证对方身份以及数据完整性保护功能。 从HTTP的规定上来看整个传输的过程都是明文传输的。HTTP包在服务器发出到客户端的过程中相当于“裸奔”,被拦截后可对数据包进行解析并读取就可以得到该发送请求里面的任何数据。甚至可以知道Cookie的信息(一般存储用户的会话信息,截取后去模仿用户的登录情况,就可以去请求用户的登录数据;如果可以在中间层抓取某一个网站的所有请求和返回的数据,就完全可以拿到用户在这个网站上的所有数据),这是很危险的。所以HTTP本身是没有安全属性的,它是一个明文传输的过程,一旦被截取就有可能导致信息泄露,故推荐不要把重要信息用HTTP明文传输。 请求信息明文传输,容易被窃听截取。 数据的完整性未校验,容易被篡改。 没有验证对方身份,存在冒充危险。
2.2 TCP连接的“三次握手”和“四次挥手”
1)三次握手(Three-Way Handshake):三次握手即TCP连接的建立,连接必须是一方主动打开,另一方被动打开。 握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”: ·第一次:客户端向服务端发送一段TCP报文,其中:标记位为SYN(同步序号标志,用于建立连接),表示“请求建立新连接”;序号Seq=X(X一般为1);随后客户端进入SYN-SENT阶段。 ·第二次:服务端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,其中:标志位为SYN和ACK(确认序号标志),表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”;序号Seq=y;确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。 ·第三次:客户端接收到来自服务端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP握手报文。其中:标志位为ACK,表示“确认收到服务器端同意连接的信号”;序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;随后客户端进入ESTABLISHED阶段。服务端收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。 在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成。 此后连接建立,客户端和服务器端进行正常的数据传输,“三次握手”结束。
通俗理解: ·客户端->服务端:你好,咱们交流(SYN)一下吧;我叫小克(seq=x)。 ·服务端->客户端:你好,那就交流(SYN)一下吧;小克(ACK,ack=x+1);我叫小夫(seq=y)。 ·客户端->服务端:嗯,好的我在(seq=x+1);小夫(ACK,ack=y+1)。 ·交流中…
2)四次挥手(Four-Way Wavehand):即TCP连接的释放(解除),连接的释放必须是一方主动释放,另一方被动释放。 挥手之前主动释放连接的客户端结束ESTABLISHED阶段。随后开始“四次挥手”: ·第一次:首先客户端想要释放连接,向服务端发送一段TCP报文,其中:标记位为FIN(终止连接标志),表示“请求释放连接“;序号为Seq=U;客户端进入FIN-WAIT-1阶段,即半关闭阶段,停止从客户端向服务端发送非确认报文外的数据,但仍能接收从服务端传输过来的数据 ·第二次:服务端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:标记位为ACK,表示“接收到客户端发送的释放连接的请求”;序号为Seq=V;确认号为Ack=U+1,表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值;随后服务器端开始准备释放服务器端到客户端方向上的连接。客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段。 前"两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了。 ·第三次:服务端发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:标记位为FIN,ACK(不是确认收到服务器端报文的确认报文),表示“已经准备好释放连接了”。序号为Seq=W;确认号为Ack=U+1;表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。随后服务端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止从服务端到客户端的方向上发送数据,但服务端仍然能够接收从客户端传输过来的数据。 ·第四次:客户端收到从服务端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,其中:标记位为ACK,表示“接收到服务器准备好释放连接的信号”。序号为Seq=U+1;表示是在收到了服务器端报文的基础上,将其确认号Ack值作为本段报文序号的值。确认号为Ack=W+1;表示是在收到了服务器端报文的基础上,将其序号Seq值作为本段报文确认号的值。随后客户端开始在TIME-WAIT阶段等待2MSL。服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务端到客户端方向上的连接。客户端等待完2MSL之后,结束TIME-WAIT阶段,进入CLOSED阶段,由此完成“四次挥手”。 后“两次挥手”既让客户端知道了服务端准备好释放连接了,也让服务器端知道了客户端了解了自己准备好释放连接了。于是,可以确认关闭服务器端到客户端方向上的连接了。 此后,连接释放,“四次挥手”结束。
通俗理解: ·客户端->服务端:不早了,不聊了(FIN);行吗(seq=u)。 ·服务端->客户端:不聊了(FIN);行(ack=u+1);我再给你说最后一句(seq=v)。 ·服务端->客户端:不聊了(FIN);行(ack=u+1);你把欠我的100块还了(seq=w)。 ·客户端->服务端:不聊了(FIN);我出来急没带钱(seq=u+1);下次一定(ack=w+1)。 ·各回各家各找各妈中…
3)三四的差别从何而来? ·建立连接时,被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备,可以直接返回SYN和ACK报文,开始建立连接。 ·释放连接时,被动方服务器,突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE-WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。 所以是“三次握手”,“四次挥手”。
2.3 HTTPS的四次握手
HTTP的“三次握手”过程仅仅是用来确认网络是否连通。HTTPS的“四次握手”过程会相对复杂一点,因为需要有加密传输的过程,并且客户端和服务端之间还需要确定最后数据传输时真正使用的秘钥。 ·第一次:客户端生成一个随机数(客户端随机数K),传输到服务器端,中间会带上客户端这边支持的加密套件(存在许多不同的加密方法)。 ·第二次:服务端存储客户端随机数K,也生成一个随机数(服务端随机数F),将服务端随机数F与公钥(服务器端证书),一起传输给客户端。 ·第三次:客户端通过服务端传过来的公钥(服务端证书)生成一个新的随机数(预主秘钥Y)。将预主密钥用公钥加密之后再传输到服务器端。 在这个过程中由于客户端使用了公钥对数据进行加密,即使中间人截取到了数据包没有私钥便无法对数据进行解密,只有服务器端有私钥才可以对数据进行解密。 ·第四次:服务端通过私钥解密拿到了预主秘钥。然后客户端和服务端同时对这三个随机数(K、F、Y)进行算法操作生成一个主密钥(Z)。 这里的算法会涉及到一个加密套件,因为最终服务器端会选择一个客户端发送过来的加密套件,然后两边同时使用这个加密套件对三个随机数进行一个算法的操作才会生成一个主密钥。 有了这个主密钥之后,两边传输的数据都通过这个主密钥进行加密。由于两边主密钥是一样的所以两边都能够对加密的数据进行机密,得到真正的数据。而中间人因为没办法知道主密钥,即使截取了数据包也没有办法对数据进行解密。所以这中间的数据传输就是安全的。