前端学习体系(2)--HTTP协议

971 阅读20分钟

前言

今天继续来整理关于前端的一个知识体系的HTTP协议部分,这也是对前端而言非常重要的一部分,来讲讲我对HTTP协议的理解,因所学有限,因此如果有什么错误的地方,欢迎大家指正。

HTTP概述

先来简单说下HTTP的一些概念

  • HyperText Transfer Protocol 超文本传输协议其实也可以被称为超文本转移协议
  • 我们把一系列与互联网关联的协议集合起来称之为TCP/IP
  • 我们所说的HTTP其实是属于TCP/IP协议族内部,是它的一个内部子集,通俗来说就是HTTP是这么多协议中的一种
  • HTTP是属于五层模型中的应用层,下面会提到这个分层模型

HTTP历史版本

  • HTTP/0.9 HTTP标准还未建立,因此一般1.0之前的版本都为0.9版本
  • HTTP/1.0 正式发布标准版本,称为HTTP/1.0
  • HTTP/1.1 目前的主流版本,也是被广泛使用的版本
  • HTTP/2.0 未来的版本,还有待完善

URI和URL

谈到HTTP,相信和我们日常生活中输入网址查询资料,那个网址就是我们HTTP协议中非常重要的一环,我们所谓的网址有以下三种类型

URI Uniform Resource Identifier 统一资源标识符

URL Uniform Resource Location 统一资源定位符

URN Unifrom Resource Name 统一资源名

URL和URN其实都是属于URI的子集,也就是说我们平常说的网址其实都可以叫做URI。另外URN大家可能知道的比较少,URN表示资源的特定内容的唯一名称,与目前资源所在地无关,因此使用这些URN,就可以随意将资源四处转移,而不担心需要去换地址了,目前URN还在实验阶段,基本也是用不上的,简单了解即可。

HTTP首部和状态码

先来看下HTTP报文的一个大概的结构

这个是笔者使用fiddler抓取请求的一些信息,上面这些其实就是我们的报文信息,第一个是请求报文,第二个是响应报文,总结上面的一个报文结构,于是就有了下面的这个HTTP的报文结构

HTTP的报文结构

起始行
报文首部(各种关于HTTP传输的重要信息都包含在首部中)
空行(CRLF)
报文主体(客户端所需要的资源)

需要了解的是,这里的起始行对于请求报文和响应报文来说结构都是固定的

  • 请求报文 请求方法+路径+HTTP/版本号
  • 响应报文 HTTP/版本号+状态码+状态短语

HTTP常用的报文首部

常用的首部字段被分为四种

  • 通用首部字段,表示请求报文和响应报文都会使用的字段
  • 请求首部字段,即客户端向服务端发送请求的首部字段
  • 响应首部字段,服务端响应客户端的首部字段
  • 实体首部字段,表示请求和响应报文中实体部分使用的首部字段

常用的各个分类的首部字段,可以去这里查询

HTTP状态码

通过查看响应报文,我们可以看到上面的起始行给出了一个响应的状态码,其实就是代表一系列响应信息的一个数字代码,200就表示响应成功的意思,每个响应码的第一位代表了状态码的分类,状态码有一下几个分类 | | 5XX |服务端错误| 表示服务器处理请求错误 |

状态码 分类 描述
1XX 信息型 表示请求正在处理
2XX 成功型 表示请求正常处理
3XX 重定向 表示需要进行附加操作完成请求
4XX 客户端错误 表示服务器无法处理求
5XX 服务端错误 表示服务器处理请求错误

一般状态码后面都会加上一个原因短语,用来说明状态码的含义,像是上面展示的200 ok,‘ok’就是我们所说的原因短语。 一些常见的具体状态码,像是200、404、500等大家都很熟悉,就不再细说了,这里给大家分享一下一些可能不怎么常见的状态码,但是日后可能会遇到的状态码

206 Partial Content

表示客户端请求资源的部分内容,而服务器成功响应了部分的资源内容的状态码,并且会响应报文中会带上Content-Range的指定范围的实体内容

302 Found

临时性重定向,表示资源已经临时转移到其他URL上,希望用户本次访问新的URL,返回的响应报文中会携带Location字段显示新的URL

403 Forbidden

表示请求的资源被服务器拒绝了,服务器可以在实体中声明拒绝的原因,也可以不说明,一般表示权限出现了某些问题

503 Service Unavailable

表示服务器正在进行超负载或者停机维护的状态,现在无法处理请求,如果得知解决以上状况所需的时间,可以写入Retry-After字段返回给客户端

我们会经常遇到状态码和实际状况不一致的情况,其实这就是在开发的时候,可能并没有遵守各个响应码所代表的含义,就直接返回给客户端了,但是这样做不好的地方在于没有标准,后来的人可能很难去维护前人的代码。

HTTP缓存

关于缓存问题,其实是非常复杂的一个问题,笔者之前也是以为缓存非常简单,但是实际比我们想象的更复杂,这里说的缓存严格意义上来说其实就是客户端缓存,就是保存在浏览器端的资源的副本,通过一些简单首部字段控制缓存行为,那么缓存究竟是什么呢?

缓存就是自动保存文档的副本,可以解决冗余的数据传输、带宽限制、服务器响应速速以及网络延迟等问题

下面就说说这几个有关缓存的HTTP的首部字段,关于缓存的深入了解,笔者也还在了解中,就暂时不误人子弟了

  • Pragma HTTP1.1之前的版本遗留的字段,只有一个值no-cache表示强制要求缓存服务器去源服务器验证资源的有效性
  • Cache-Control 控制缓存的行为,请求报文和响应报文中可能都会有这个字段,有以下几个常见的值,来控制相应的行为

public 用作响应报文,表示任何客户端都可以获得响应缓存

private 用作响应报文,表示只有指定的用户可以获得缓存

no-cache 作为请求报文时,是指强制请求服务器验证缓存,在服务器端作为响应报文的话,是指每次缓存前确定资源的有效性

no-store 不论是什么报文,是表示不缓存请求和响应

Expires 表示资源失效的时间,意思就是在指定的时间内的资源副本,会被当做缓存返回给客户端,如果在指定时间之后的话,则会请求源服务器获取资源

max-age 作为请求报文字段时,表示如果缓存资源的缓存时间不超过设置的时间,则客户端接收缓存资源。如果是作为服务器响应报文的话,则表示当前资源保存的最长的时间。需要注意的是,在HTTP1.1版本的时候,如果同时遇到Expires字段时,会忽略该字段,先处理max-age字段,但是在HTTP1.0时,则相反先处理Expires字段

ETag 表示告知客户端资源实体的标识符,是一种将资源以字符串形式做唯一的标识性的方式,一般都是服务器来进行分配。需要知道的是,ETag有强弱之分,强ETag值表示无论实体发生多么微小的变化,都会更新其值,而弱ETag则表示资源是否相同,只有资源产生根本性差异,才会改变其值,这时会在字段开始处附加w/,如下所示:

ETag: W/"123456"

If-Match 表示只有匹配的ETag值和服务器返回的ETag值一致时才会返回请求,反之则会返回412 Precondition Failed状态码

If-None-MatchIf-Match字段刚好相反,表示与返回ETag字段不一致时返回,则处理该请求

If-Modified-Since 表示资源在指定的日期以后有更新过,则服务器接收请求,反之则会返回304 Not Modified,指资源在指定的日期之后没有被修改过,可以使用缓存

If-Unmodified-Since 这个字段与上面的刚好相反,表示在指定日期之后未发生更新,才能处理请求,否则返回412 Precondition Failed

If-Range 表示指定的值如果和返回的ETag的值,或者Date日期的值一致,则会被当做范围请求来处理,反之则会返回全部资源

下面是一个展示缓存流程的步骤图:

  1. 当请求到达服务器或者是代理时,判断是否有缓存;
  2. 如果没有缓存的话直接从服务器获取,然后存入缓存中;
  3. 如果有缓存,则会与服务器验证新鲜度;
  4. 如果缓存新鲜度足够,则对缓存的新鲜度进行更新;
  5. 如果新鲜度不够则请求服务器获取,回到第二步;

安全的HTTPS

虽然HTTP非常的方便好用,但是因为它是明文传输,所以很容易被别人窃取其中的内容,因此为了防止这种情况的出现,就有了我们的HTTPS的出现。

先来看下HTTPS的定义

我们把添加了加密及认证机制的HTTP称为HTTPS,即HTTP Secure --摘自《图解HTTP》

那么什么叫做加密以及认证机制呢?我们一步步来说。

要知道HTTPS本质其实还是使用HTTP协议的,所不同的地方在于HTTP是直接明文和TCP通信的,而HTTPS则是利用了SSL(Secure Socket Layer)和TLS(Transport Layer Security)协议,用他们来和TCP进行传输,换言之,就是在HTTP协议外面报了一层SSL的壳,就称为HTTPS。

那么问题又来了,为什么加个壳就能安全传输了呢?这就要提到我们上面说过的加密和认证机制了。

对称加密

通信双方使用同样的密钥来对报文进行加密,这样的话别人就看不到了,但是缺点就是首次通信的时候,需要将密钥发送给对方,此时密钥都是明文的,如果被窃取的话,则通信双方的信息也就被破解了。

非对称加密

针对上面的对称加密的缺点,于是又了非对称加密。通信双方使用两把密钥,一把是私钥,即只有自己知道的秘钥,一把是公钥,是公开给所有人知道的。发送信息的一方使用自己的公钥进行加密,收到信息的一方则使用自己的私钥进行解密,这样的话就不需要将密钥发送保证了数据传输的安全。

但是针对这种情况,如果中间人窃取了数据包,更换了数据,再用公钥进行加密发送出去,这样接收方根本不知道自己收到的内容是否是发送方想要传递的信息。 另外则是虽然非对称加密安全性比较高,但是其处理效率是非常低的,如果HTTPS使用这种方式的话,那处理的速度也会非常的低,于是就有了下面的混合加密。

混合加密机制

混合加密机制则是混合了对称加密和非对称加密的优点,实现安全快速的发送信息,具体的实现思路如下:

  1. 使用非对称加密的方式,发送者将后续用于通信的对称加密的密钥使用公钥进行加密
  2. 接受者收到信息后用自己的私钥进行解密,获得对称加密的密钥
  3. 在确保交换密钥是安全的前提下,后续则可以使用对称加密的密钥进行通信

这样做既实现了安全,又实现了效率的提高,但是还有一个问题,就是上面的非对称加密的一个缺陷,即我们如何保证我们在第二步收到的信息中的密钥就是发送者开始发送的密钥呢?

这里人们又想出来一个想法(ps:不得不感慨人类的智慧真的是无穷的),由可信任的第三方数字证书认证机构颁发公开密钥证书,这样的话,我们上面的三步通信方式则发生了如下的改变

  1. 服务器将自己的公钥登陆至数字证书认证机构
  2. 数字证书认证机构根据服务器的公钥,利用自己的私钥,进行部署签名和颁发公钥证书
  3. 客户端拿到数字证书认证机构的公钥证书以后,利用其公开的密钥向数字证书认证机构验证公钥证书上的签名,确保服务器公钥的真实性
  4. 确认服务器的公钥无误以后,则利用公钥对报文加密以后发送
  5. 服务器拿到报文以后,使用自己的私钥进行解密,这样就获取了服务器的公钥

相比上面的步骤,这里则是多了一个第三方的数字证书认证机构颁发证书签名的步骤,关于数字证书签名怎么获取,颁发等等就不展开,有兴趣的同学可以上网搜搜,当然认证机构的公开密钥怎么安全的转交客户端其实也是一个问题,所以一般来说,浏览器开发商会事先在浏览器中植入常用认证机关的公开密钥

这里就是一个csdn网站的一个相关的整数信息

其实以上这些就是我们在开头所说的SSL和TLS协议的一个实现,我们的HTTPS就是在以上这些内容中实现的,那么同样的HTTPS其实也会具有上面的一些不足的地方,就是效率会比HTTP低很多,因为需要不断的进行加密和解密的操作,会消耗大量的CPU和内存等资源,因此处理速度也是相对比较慢的。

TCP/IP协议族

上面的HTTPS也是说到了我们是利用SSL和TLS来和TCP进行通信的,那么TCP又是什么呢,别急,我们慢慢道来。 首先我们的HTTP协议其实是属于TCP/IP协议族中的一个内部子集,而TCP则是这个协议族的重要组成部分。

TCP/IP协议族的一个突出思想就是分层,为什么要采用分层呢,其实简单来说就是各司其职,减少耦合,这样后续如果各层进行更新升级不会影响到其他层的协议了,现在主流的或者说是主要的就是以下的五层模型:

  • 应用层面向用户,为用户提供直接服务,如HTTP,FTP,DNS都是属于应用层
  • 传输层包含两个性质不同的协议TCP(传输控制协议)和UDP(用户数据报协议)
  • 网络层处理在网络上流动的数据包
  • 网络链路层链接硬件设备,诸如硬件驱动,操作系统等
  • 物理层负责数据传输的硬件设备,如电话线路,以太网等

另外还有一个七层的osi分层模型,就是在应用层里面细分出了表现层和会话层

  • 表示层 表示层把数据转换为合适、可理解的语法和语义
  • 会话层 维护网络连接的状态

知道了这些,我们大概就知道了以上说的所有的知识点的一个大概层次结构了,那么我们接着TCP往下说说是如何进行TCP的连接以及TCP协议的一些相关信息

TCP协议

  • TCP位于传输层,提供字节流服务(Byte Stream Service),即大数据块分割成以报文段为单位的数据包进行管理
  • 可以将数据准确可靠的传递给对方

TCP的三次握手就是为了准确无误的将数据送到目标处

  • 客户端先发送一个带有SYN标志的数据包给对方
  • 服务端接受到以后,回传一个带有SYN/ACK标志的数据包表示确认收到的信息
  • 客户端再发送一个ACK标志的数据包,表示握手结束

若握手过程中某个阶段链接断开了,则TCP协议会以相同的顺序再次发送数据包

TCP四次挥手确认断开链接

  • 第一次挥手:客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态。
  • 第二次挥手:服务端收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务端进入CLOSE_WAIT状态。
  • 第三次挥手:服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态。
  • 第四次挥手:客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务端,确认序号为收到序号+1,服务端进入CLOSED状态,完成四次挥手。

说完了TCP,之后就是IP协议,也就是存在于网络层的IP协议,用来处理TCP传过来的数据包,这部分只是简单认识一下,因为我对下面这些了解的也不多了(手动狗头)

IP协议

位于网络层,IP(Internet Protocol)即网际协议,IP协议的作用把各种数据包传送给对方

IP地址

通俗来说就是你上网的位置,即当前网络被分配到的地址,上网的位置是随时可变的,因此IP地址也是可以变的

MAC地址

网卡所属的固定地址,这个是商家指定分配的,是不可变的

ARP协议

解析地址的协议,根据对方的IP地址来解析对应的MAC地址

DNS

提供域名到IP地址之间的解析服务

那么将以上这些连接起来,就形成了一个完整的从请求到响应的过程了,在浏览器窗口输入URL,由DNS解析域名,分离IP地址和端口号,HTTP协议则将信息包装成报文进行发送,TCP协议负责将报文分段进行传输,将数据包发送给下一层,即网络层,IP协议则搜索目标地址,进行传送,利用ARP协议获取MAC地址,增加作为通信目的地的MAC地址,将数据转发给链路层。服务端接受也是按照相反顺序从HTTP协议中获取请求。

Web的攻击技术

了解完基本的HTTP知识后,安全问题也是我们一直不得不去重视的另外一个问题,这里所说的一些攻击技术,也是基于笔者本人所了解的,如果有疏漏或者错误,欢迎大家尽早提出呀。

针对Web应用的攻击分为两种

  • 主动攻击
  • 被动攻击

顾名思义,主动攻击,即攻击者直接访问Web应用,将攻击代码传入,而被动攻击,则是利用圈套策略执行攻击代码的攻击模式。 主动攻击主要有SQL注入攻击,被动攻击则主要是XSS攻击和CSRF攻击等,下面就来说说这几种攻击。

SQL注入

针对Web应用使用的数据库,运行非法的SQL而产生的攻击。

用我自己的话来说的话就是,由于服务端运行SQL一些动态SQL的时候,没有对动态的内容进行过滤,导致一些关键词被使用,从而产生了意想不到的执行结果。

XSS攻击

跨站脚本攻击,即运行了非法的JS脚本或者HTML标签,导致页面的内容被篡改或者信息被泄露

简单解释一下的话,就是在页面的输入框等地方,没有对输入内容进行过滤,导致运行了一些非法的JS脚本和HTML标签,导致这个问题的主要原因就是Web端的验证和服务器端的验证没有对一些特殊的标签和关键字进行过滤,即输出值转义不完全引起的安全漏洞。

CSRF攻击

跨站请求伪造

指攻击者通过设置好的陷阱,强制对已完成认证的用户进行非预期的个人信息或设定信息等某些状态更新,属于被动攻击

这里说下跨站请求伪造的一个简单的过程

  1. 用户通过登录获取认证信息登录网站
  2. 攻击者布下陷阱,诱使用户点击非法链接触发陷阱
  3. 用户点击链接发送请求时,会带上网站的认证信息,这样就等于攻击者窃取了用户的身份,可以在网站进行用户的操作

一般的防御方案,就是使用token进行验证用户的请求或者是使用验证码,使用自定义的字段来验证请求等都是可以来防御CSRF攻击

上面的请求字段x-csrf-token就是一个自定义的验证字段,用来防止csrf的攻击,这个也是从笔者的个人网站中截取的部分,地址在下面已经提供,关于web安全,笔者了解的还比较片面,也欢迎大佬们补充。

后记

笔者会将这些文章详细信息放在个人博客中,当然个人博客现在还只是初步阶段完善中,欢迎大家给笔者留言或者是建议等。

参考资料