问不倒的HTTP协议
AhuntSun 人气:0
## 一、HTTP简介
### 1.HTTP
**HTTP:**超文本传输协议,是一种**通信协议**;允许超文本标记文档从`Web`服务器传送到客户端的浏览器中。
简单:传输`html`文件的协议。
**Web:**是一种基于超文本和`HTML`的、全球性的、动态交互的、跨平台的分布式**图形信息系统**。
`http`是**无状态协议**,这保证了它的高效。`Cookie`和`Section`的出现使`http`在保持高效的情况下,能够记住状态;
### 2.URI与URL
![image-20200318091045352](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/0.png)
* `URI`可分为`URL`,`URN`或同时具备`locators` 和` names`特性的东西;
* `URN`的作用就好像一个人的名字,`URL`就像这个人的地址;
* 换句话说:`URN`确定了东西的身份,`URL`提供了找到它的方式;
**URL是URI的一种,不是所有的URI都是URL;URI唯一地标识了身份,URL给出了访问机制(http/ftp/telnet等)**
## 二、状态码
![image-20200318115514752](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/1.png)
#### 1xx:接收的请求正在处理
#### 2xx:请求正常处理完毕
| 状态码 | 状态码英文名称 | 描述 |
| :----: | :-------------: | :----------------------------------------------------------: |
| 200 | OK | 请求已成功,请求所希望的响应头或数据体将随此响应返回 |
| 202 | Accepted | 已接受,已经接受请求,但未处理完成 |
| 204 | No Content | 请求处理成功,但是返回的响应报文中不包含实体的主体部分 |
| 206 | Partial Content | 该状态码表示客户端进行了范围请求, 而服务器成功执行了这部分的
`GET` 请求。 响应报文中包含由 `Content-Range` 指定范围的实体内容。 | #### 3xx:重定向 | 状态码 | 状态码英文名称 | 描述 | | ------ | :---------------: | :----------------------------------------------------------: | | 301 | Moved Permanently | 永久重定向,请求的资源已被永久的移动到新的`URI`,返回信息会包括新的`URI`,浏览器会自动定向到新的`URI`。今后任何新的请求都会使用新的`URI`(比如某的网站域名已更改,访问旧网址会自动跳转到网址) | | 302 | Found | 暂时重定向,与`301`类似。但资源只是临时被移动,客户端应继续使用原有的URI | | 303 | See Other | 该状态码表示由于请求对应的资源存在着另一个` URI`, 应使用 `GET`
方法定向获取请求的资源。与`302`区别在于`303`希望用户使用`GET`访问新的`URI`,而`302`可以使用`POST`访问新的`URI` | | 304 | Not Modified | 该状态码表示客户端发送附带条件时(`If-Match`, `If-ModifiedSince`等), 服务器端允许请求访
问资源, 但未满足附带的条件。 此时返回,`304` 状态码, 不包含任何响应
的主体部分。另一种理解:**所请求的资源没有更改,可以使用缓存** | #### 4xx:客户端错误 | 状态码 | 状态码英文名称 | 描述 | | :----: | :------------: | :----------------------------------------------------------: | | 400 | Bad Request | 客户端请求报文语法错误,服务器无法理解 | | 401 | Unauthorized | 表示发送的请求需要有通过` HTTP `认证(`BASIC` 认证、
`DIGEST `认证) 的认证信息 | | 403 | Forbidden | 服务器理解客户端的请求,但是拒绝执行此请求 | | 404 | Not Found | 服务器无法根据客户端的请求找到资源(网页) | #### 5xx:服务器错误 | 状态码 | 状态码英文名称 | 描述 | | :----: | :-------------------: | :----------------------------------------------------------: | | 500 | Internal Server Error | 服务器端内错误或` Web`
应用存在`bug`或某些临时的故障,导致无法完成请求 | | 502 | Bad Gateway | 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求 | | 503 | Service Unavailable | 表明服务器暂时处于超负载或正在进行停机维护, 现在无法
处理请求 | ## 三、HTTP首部 ### 1.HTTP请求和响应报文 #### 1.1HTTP请求报文 ![image-20200317202609927](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/2.png) ![image-20200318103054848](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/3.png) #### 1.2.HTTP响应报文 ![image-20200317202637972](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/4.png) ![image-20200318103225790](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/5.png) 可见HTTP报文一共有**四种**首部字段(请求头):**请求首部字段、响应首部字段、通用首部字段、实体首部字段;** #### 1.3.示例 在`chrome`的开发者调试工具当中,从请求报文和响应报文分各抽出了一部分,形成了三部分: **General:** ![image-20200318105143441](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/6.png) **Request Headers:** ![image-20200318105327277](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/7.png) **Response Headers:** ![image-20200318105410254](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/8.png) ### 2.请求首部字段 ![image-20200317203914289](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/9.png) #### 2.1.Accept 作用:**浏览器端可以接受的媒体类型;** ![image-20200318095255629](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/10.png) 若想要给显示的媒体类型增加优先级, 则使用 `q`来额外表示权重值,用分号`(;)`进行分隔。权重值` q` 的范围是` 0~1`(可精确到小数点后` 3` 位) ,且` 1 `为最大值。不指定权重` q` 值时,默认权重为 `q=1.0`。 当服务器提供多种内容时,将会首先返回权重值**最高**的媒体类型。 #### 2.2.Accept-Charset 作用:用来通知服务器用户代理(浏览器)支持的字符集及字符集的相对优先顺序。 ![image-20200318095604225](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/11.png) 图Accept-Charset字段中的值: ``` Accept-Charset: iso-8859-5, unicode-1-1;q=0.8 ``` 中的`unicode-1-1;q=0.8`是一个整体,表示unicode编码优先级为0.8,小于默认的iso编码优先级(默认q=1);**不要以为分号(;)为分割符,其实逗号(,)才是分割符** #### 2.3.Accept-Encoding 作用:用来告知服务器用户代理支持的内容编码及内容编码的**优先级顺序**。 可一次性指定**多种**内容编码。 ![image-20200318095930260](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/12.png) ``` Accept-Encoding: gzip, deflate ``` 常见的编码方式有:**gzip**、**compress**、**deflate**、**identity**。 #### 2.4.Accept-Language 作用:用来告知服务器浏览器能够接收的语言 ,以及相对优先级。 ![image-20200318100341589](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/13.png) ``` Accept-Language: zh-cn,zh;q=0.7,en-us,en;q=0.3 ``` 上述值表示:优先请求中文版,其次是英文版; #### 2.5.Host ![image-20200317210815624](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/14.png) ``` Host: www.hackr.jp ``` 若服务器未设定主机名,`Host`为空值即可。 #### 2.6.If-Match ![image-20200317211022050](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/15.png) 形如`If--xxx`这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。 ![image-20200317211036278](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/16.png) 上图表示:只有当`If-Match`的字段值跟`Etag`值匹配一致时,服务器才会接收请求。 #### 2.7.If-Modified-Since ![image-20200317211327966](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/17.png) 上图表示:如果在`If-Modified-Since`字段指定的日期时间后,资源发生了更新,服务器会接收请求,此时返回状态码`200`;否则会拒绝接收请求返回`304`(因为资源都没更新过,不需要重新请求),与响应头`Last-Modified`是一对; #### 2.8.If-None-Match 只有在 `If-None-Match` 的字段值与 `ETag `值不一致时, 可处理该请求。 与 `If-Match` 首部字段的作用相反; ![image-20200317211800953](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/18.png) #### 2.9.If-Range 首部字段 `If-Range` 属于附带条件之一。 它告知服务器若指定的 `If-Range` 字段值(`ETag` 值或者时间) 和请求资源的 `ETag` 值或时间相一致时, 则作为范围请求处理。 反之, 则返回全体资源。 ![image-20200317212055861](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/19.png) 下面我们思考一下不使用首部字段` If-Range` 发送请求的情况。 服务器端的资源如果更新, 那客户端持有资源中的一部分也会随之无效,当然,范围请求作为前提是无效的。这时,服务器会暂且以状态码 `412:Precondition Failed `作为响应返回, 其目的是催促客户端再次发送请求。这样一来,与使用首部字段 `If-Range `比起来,就需要花费两倍的功夫。 ![image-20200317212159337](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/20.png) #### 2.10.Referrer 作用:告诉服务器我是从哪个页面的链接过来的,服务器籍此可以获得一些信息用于处理; ![image-20200318101839032](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/21.png) ``` Referer: http://www.hackr.jp/index.htm ``` #### 2.11.User-Agent 作用:告诉HTTP服务器,客户端使用的操作系统和浏览器的名称和版本; ![image-20200318102046185](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/22.png) ``` User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/2010010 ``` 很多时候我们会通过该字段来判断浏览器类型,从而进行不同的兼容性设计。 ### 3.响应首部字段 ![image-20200317203931940](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/23.png) ![image-20200317212421283](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/24.png) #### 3.1.Age 首部字段 `Age` 能告知客户端,源服务器在多久前创建了响应。字段值的单位为秒。 ![image-20200317212504499](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/25.png) #### 3.2.ETag 首部字段` ETag` 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 `ETag`值。 另外, 当资源更新时,`ETag` 值也需要更新。生成 `ETag` 值时,并没有统一的算法规则,而仅仅是由服务器来分配。 ![image-20200317212602438](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/26.png) 与响应头`If-None-Match`是一对; #### 3.3.Location 使用首部字段` Location` 可以将响应接收方引导至某个与请求 `URI` 位置不同的资源。 基本上,该字段会配合 `3xx : Redirection` 的响应, 提供重定向的`URI`。 ### 4.通用首部字段 ![image-20200317203943920](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/27.png) #### 4.1.Cache-Control **a.请求首部中Cache-Control的指令:** ![image-20200317204206171](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/28.png) **b.响应首部中Cache-Control的指令:** ![image-20200317204635351](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/29.png) **Cache-Control各指令详解:** * **public指令:**客户端和代理服务器(`CDN`)可以缓存; * **Private指令:**只有客户端可以缓存; ![image-20200317204824663](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/30.png) * **no-store指令:**真正意义上的所有内容都不缓存(**协商缓存**); * **no-cache指令:**正确来说该指令还是会使用缓存,只不过使用前要确认其新鲜程度(**协商缓存**); ![image-20200317204854401](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/31.png) * **s-maxage = x指令 **:代理服务器请求源站缓存后的X秒内不再发出请求,只对`CDN`缓存(`CDN`指的是拥有源服务器资源的多个分布式服务器)有效; ``` Cache-Control: s-maxage=604800 //(单位 : 秒) ``` 此外,当使用 `s-maxage` 指令后,则直接忽略对 `Expires` 首部字段及`max-age` 指令的处理。 即优先级为:**`S-maxage` > `Max-age` > `Expires`** * **Max-age = x指令:**请求缓存后的X秒内不再发起请求。 ``` Cache-Control: max-age=604800 //(单位: 秒) ``` ![image-20200317204940262](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/32.png) 当**客户端**发送的请求中包含` max-age `指令时: 如果判定指定的时间比缓存资源的缓存时间数值**更大**,那么客户端就接收缓存的资源。另外,当指定 `max-age` 值为 `0`(指定时间**更小**),那么缓存服务器通常需要将请求转发给源服务器。 当**服务器**返回的响应中包含 `max-age` 指令时,缓存服务器将不对资源的有效性再作确认,而直接把 `max-age` 数值作为保存为缓存的资源的最长时效。 应用 `HTTP/1.1` 版本的缓存服务器遇到同时存在 `Expires` 首部字段的情况时,会优先处理 `max-age` 指令,而**忽略**掉 `Expires` 首部字段。 #### 4.2.Connection 有两个作用: * **控制不再转发给代理的首部字段:** ![image-20200317210000299](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/33.png) 如图中,`Connection`的值为`Upgrade`表示不将`Upgrade`这个首部发给代理; * **管理持久连接:** a.当`Connection : close` 时: ![image-20200317210148420](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/34.png) 代表一个`Request`完成后,客户端和服务器之间用于传输`HTTP`数据的`TCP`连接会关闭(四次挥手)。当客户端再次发送`Request`,需要重新建立`TCP`连接(三次握手)。 b.当`Connection:Keep-Alive` 时: ![image-20200317210232981](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/35.png) 此时,当一个网页打开完成后(已经建立TCP连接),客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器,会继续使用这条已经建立的连接; #### 4.3.Via 使用首部字段Via是为了追踪客户端与服务器之间的请求和响应报文的传输路径: ![image-20200317210436541](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/36.png) ### 5.实体首部字段 ![image-20200317203957114](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/37.png) 实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息。 ![image-20200317213108376](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/38.png) #### 5.1.Content-Type 作用:说明报文内对象的媒体类型; ``` Content-Type: text/html; charset=UTF-8 ``` #### 5.2.Expires ![image-20200317213143041](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/39.png) 首部字段 `Expires` 会将资源失效的日期告知客户端。**缓存服务器**(代理服务器)在接收到含有首部字段 `Expires `的响应后,会以缓存来应答请求,在`Expires` 字段值指定的时间之前,响应的副本会一直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。 源服务器不希望缓存服务器对资源缓存时, 最好在 `Expires` 字段内写入与首部字段 `Date` 相同的时间值。 但是,当首部字段` Cache-Control` 有指定 `max-age` 指令时,比起首部字段 `Expires`,会优先处理 `max-age `指令。 #### 5.3.Last-Modified ![image-20200317213437706](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/40.png) 首部字段 `Last-Modified` 指明资源最终修改的时间。 与请求头`If-Modified-Since`是一对; ``` Last-Modeified: Wed, 23 May 2012 09:59:55 GMT ``` ### 6.为 Cookie 服务的首部字段 `Cookie`的工作机制是用户识别及状态管理。`Web` 网站为了管理用户的状态会通过 `Web` 浏览器,把一些数据临时写入用户的计算机内。接着当用户访问该`Web`网站时,可通过通信方式取回之前发放的`Cookie`; 调用 `Cookie` 时,由于可校验 `Cookie` 的有效期,以及发送方的域、路径、协议等信息,所以正规发布的 `Cookie` 内的数据不会因来自其他`Web` 站点和攻击者的攻击而泄露。 **为 Cookie 服务的首部字段:** ![image-20200317213803615](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/41.png) #### 6.1.Set-Cookie字段 当服务器准备开始管理客户端的状态时,会事先告知各种信息。 ``` Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31 GMT; path ``` **`Set-Cookie` 字段的属性 ** ![image-20200317213949707](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/42.png) * **expires 属性:** `Cookie` 的 `expires` 属性指定浏览器可发送 `Cookie` 的有效期。当省略 `expires` 属性时,其有效期仅限于维持浏览器会话`(Session)`时间段内。 这通常限于浏览器应用程序被关闭之前。 另外,一旦 `Cookie` 从服务器端发送至客户端,服务器端就不存在可以显式删除 `Cookie` 的方法。但可通过覆盖已过期的 `Cookie`,实现对客户端 `Cookie` 的实质性删除操作。 * **domain 属性:** 通过 `Cookie` 的` domain` 属性指定的域名可做到与结尾匹配一致。 比如,当指定 `example.com` 后,除 `example.com` 以外, `www.example.com`或 `www2.example.com `等都可以发送 `Cookie`。 因此, 除了针对具体指定的多个域名发送 `Cookie `之 外,不指定`domain` 属性显得更安全。 * **secure 属性:** `Cookie` 的` secure` 属性用于限制 `Web` 页面仅在 `HTTPS` 安全连接时,才可以发送 `Cookie`。 发送 `Cookie `时,指定` secure `属性的方法如下所示: ``` Set-Cookie: name=value; secure ``` 以上例子仅当在` https://www.example.com/(HTTPS) `安全连接的情况下才会进行` Cookie` 的回收。也就是说, 即使域名相同,`http://www.example.com/(HTTP) `也不会发生 `Cookie` 回收行为。 当省略 `secure` 属性时,不论 `HTTP `还是 `HTTPS`,都会对 `Cookie` 进行回收。 * **HttpOnly 属性:** `Cookie` 的 `HttpOnly `属性是 `Cookie` 的扩展功能,它使 `JavaScript `脚本无法获得 `Cookie`。 其主要目的为防止跨站脚本攻击`(Cross-sitescripting, XSS)` 对` Cookie` 的信息窃取。 发送指定 `HttpOnly` 属性的` Cookie` 的方法如下所示。 ``` Set-Cookie: name=value; HttpOnly ``` 通过上述设置,通常从` Web `页面内还可以对 `Cookie `进行读取操作。但使用 `JavaScript` 的 `document.cookie` 就无法读取附加` HttpOnly` 属性后的` Cookie `的内容了。 因此,也就无法在 `XSS` 中利用 JavaScript 劫`Cookie` 了。 #### 6.2.Cookie字段 首部字段 `Cookie` 会告知服务器,当客户端想获得 `HTTP `状态管理支持时, 就会在请求中包含从服务器接收到的 `Cookie`。 接收到多个`Cookie` 时,同样可以以多个 `Cookie `形式发送。 ``` Cookie: status=enable ``` ## 四、HTTP请求方法 **HTTP/1.1 的常用方法 :** ![image-20200318104329280](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/43.png) ### 1.GET `GET `方法用来请求访问已被` URI` 识别的资源。指定的资源经服务器端解析后返回响应内容。 举例: ![image-20200318104711164](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/44.png) ![image-20200318105633396](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/45.png) **GET方法也可以用来提交表单和其他数据:** ``` http://localhost/login.php?username=aa&password=1234 ``` 从上面的请求`URL`中,很容易就能辨认出表单提交的内容。`HTTP0.9`的时候只有`GET`方法,所以`GET`方法既能获取数据,也能提交数据,只不过提交的数据是拼接在`URL`后的不能提交太多且不安全;提交大量数据时使用`POST`方法。 ### 2.POST * `POST`方法功能与`GET`方法类似,是`GET`方法的延伸,主要用于向服务器提交数据量较大的**用户表单**数据; * 提交的数据放在请求报文的主体中,保证了提交数据的安全;这样就克服了`GET`方法提交的数据量太小和不能保密的缺点。 * `POST`方法的主要目的并不是获取响应主体的内容; ![image-20200318110800869](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/46.png) ### 3.PUT * `PUT`方法用来传输文件。 就像` FTP` 协议的文件上传一样, 要求在请求报文的主体中包含文件内容, 然后保存到请求` URI `指定的位置。 * `PUT`方法和`POST`很相似,最大的不同是:`PUT`是幂等的,`POST`是不幂等的。 即创建文件使用`POST`更新文件使用`PUT`; > 幂等:幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同; * 但是, 鉴于·`HTTP/1.1` 的 `PUT `方法自身不带验证机制, 任何人都可以上传文件 , 存在安全性问题, 因此一般的 `Web `网站**不使用该方法**。 ### 4.HEAD `HEAD` 方法和 `GET` 方法一样, 只是获取响应报文首部,不返回报文主体部分。 用于确认`URI` (超链接)的有效性及资源更新的日期时间等。 例如: ![image-20200318112642135](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/47.png) ### 5.DELETE * `DELETE` 方法用来删除文件,是与 `PUT` 相反的方法。`DELETE` 方法按请求 `URI` 删除指定的资源。 * 但是,`HTTP/1.1 `的 `DELETE` 方法本身和 `PUT `方法一样不带验证机制,所以一般的 `Web `网站也不使用 `DELETE` 方法。(怎么可能让人随便`rm -rf`) 举例: ![image-20200318113012177](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/48.png) ### 6.OPTIONS `OPTIONS `方法用来查询针对请求` URI` 指定的资源支持的方法。 ![image-20200318113110813](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/49.png) 示例: ![image-20200318113127546](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/49.5.png) ### 7.TRACE * 客户端通过 `TRACE` 方法可以查询发送出去的请求是怎样被加工修改/ 篡改的。 这是因为, 请求想要连接到源目标服务器可能会通过代理中转, `TRACE` 方法就是用来确认连接过程中发生的一系列操作。 * 但是,` TRACE` 方法本来就不怎么常用, 再加上它容易引发`XST`(`Cross-Site Tracing`, 跨站追踪) 攻击, 通常就更不会用到了。 * 发送请求时, 在 `Max-Forwards` 首部字段中填入数值, 每经过一个服务器端就将该数字减 `1`, 当数值刚好减到 `0 `时, 就停止继续传输, 最后接收到请求的服务器端则返回状态码` 200 OK `的响应。 ![image-20200318114809722](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/50.png) 示例: ``` //请求 TRACE / HTTP/1.1 Host: hackr.jp Max-Forwards: 2 响应: HTTP/1.1 200 OK Content-Type: message/http Content-Length: 1024 TRACE / HTTP/1.1 Host: hackr.jp Max-Forwards: 2(返回响应包含请求内容) ``` ### 8.CONNECT `CONNECT `方法要求在与代理服务器通信时建立隧道, 实现用隧道协议进行` TCP` 通信。 主要使用 `SSL`(`Secure Sockets Layer`, 安全套接层) 和` TLS`(`Transport Layer Security`, 传输层安全) 协议把通信内容加 密后经网络隧道传输。 ```http //格式 CONNECT 代理服务器名:端口号 HTTP版本 //例子 //请求 CONNECT proxy.hackr.jp:8080 HTTP/1.1 Host: proxy.hackr.jp //响应 HTTP/1.1 200 OK(之后进入网络隧道) ``` ## 五、HTTP状态管理 Cookie和Session,实现了HTTP的状态管理,Cookie是在客户端的,Session是在服务器的。 ### 1.Cookie `HTTP` 是**无状态协议**(高效率,不记仇),它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。 假设要求登录认证的` Web` 页面本身无法进行状态的管理(不记录已登录的状态) ,那么每次跳转新页面不是要再次登录,就是要在每次请求报文中附加参数来管理登录状态。 ![image-20200318090108406](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/51.png) 保留无状态协议这个特征的同时又要解决类似的矛盾问题,于是引入了` Cookie `技术。`Cookie `技术通过在请求和响应报文中写入` Cookie `信息来控制客户端的状态。 * `Cookie`实际上是一小段文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个`Cookie`; * 客户端浏览器会把`Cookie`保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该`Cookie`一同提交给服务器。服务器检查该`Cookie`,以此来辨认用户状态。 在一个网站地址栏输入: ``` javascript:alert(document.cookie) ``` 可以弹出该网站的`Cookie`信息: ![image-20200318125635655](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/52.png) `Cookie` 会根据从服务器端发送的响应报文内的一个叫做 `Set-Cookie` 的首部字段信息, 通知客户端保存`Cookie`。当下次客户端再往该服务器发送请求时, 客户端会自动在请求报文中加入 `Cookie` 值后发送出去。 服务器端发现客户端发送过来的` Cookie `后, 会去检查究竟是从哪一个客户端发来的连接请求, 然后对比服务器上的记录, 最后得到之前的状态信息。 #### 第一次:没有 Cookie 信息状态下的请求 ![image-20200318090429111](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/53.png) * **请求报文(没有 Cookie 信息的状态)** ![image-20200318090524295](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/54.png) * **响应报文(服务器端生成 Cookie 信息) ** ![image-20200318090543542](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/55.png) #### 第二次:存有 Cookie 信息状态的请求 ![image-20200318090456328](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/56.png) * **请求报文(自动发送保存着的 Cookie 信息) ** ![image-20200318090609670](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/57.png) ### 2.Session * `Session`是另一种记录客户状态的机制,保存在**服务器**上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上; * 客户端浏览器再次访问时只需要从该`Session`中查找该客户的状态就可以了; ![image-20200318140020730](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/58.png) `Cookie`和`Session`非常相似,`Cookie`相当于客户端持有的**通行证**,Session相当于服务器上的**通行名册**。 **保存Session ID的方式** * `Cookie` * `URL`重写 * 隐藏表单 **Session的有效期** * `Session`超时失效:被动失效,如果超过规定时间没有再次访问服务器,`Session`将失效; * 程序调用`HttpSession.invalidate()`:主动失效; * 服务器进程被停止; ### 3.**Token** **Token的引入** `Token`是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,`Token`便应运而生。 **Token的定义** `Token`是服务端生成的一串字符串,以作客户端进行请求的一个**令牌**,当第一次登录后,服务器生成一个`Token`便将此`Token`返回给客户端,以后客户端只需带上这个`Token`前来请求数据即可,**无需再次带上用户名和密码**。最简单的`token`组成`:uid`(用户唯一的身份标识)、`time`(当前时间的时间戳)、`sign`(签名,由`token`的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接`token`请求服务器)。 **使用Token的目的** `Token`的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。 **Session管理及Cookie应用** ![image-20200318154807240](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/59.png) * **步骤 1**:客户端把用户 `ID` 和密码等登录信息放入报文的实体部分,通常是以 `POST `方法把请求发送给服务器。而这时,会使用 `HTTPS`通信来进行` HTML`表单画面的显示和用户输入数据的发送。 * **步骤 2**:服务器会发放用以识别用户的 `Session ID`。通过验证从客户端发送过来的登录信息进行身份认证, 然后把用户的认证状态与`Session ID `绑定后记录在服务器端。 向客户端返回响应时,会在首部字段`Set-Cookie `内写入 `SessionID`(如 `PHPSESSID=028a8c…`) 。 为防止`Session ID` 被第三方盗走,服务器端需要对其进行有效性管理;并且为减轻跨站脚本攻击`(XSS)` 造成的损失,建议事先在 `Cookie`内加上 `httponly` 属性。 * **步骤 3**: 客户端接收到从服务器端发来的 `Session ID `后,会将其作为`Cookie` 保存在本地。下次向服务器发送请求时,浏览器会自动发送`Cookie`,所以 `Session ID` 也随之发送到服务器。服务器端可通过验证接收到的 `Session ID` 识别用户和其认证状态。 ### 4.Cookie与Session的区别 * **存放位置不同**:`Cookie`存放在客户端,`Session`保存在服务器端; * **安全性(隐私策略)不同**:`Cookie`存储在浏览器中,对客户端是可见的,客户端的一些程序可能会窥探或修改`Cookie`的内容;而`Session`存储在服务器端,对客户端来说是透明的;如果想要使用`Cookie`需要对其进行加密; * **有效期上的不同**:设置`Cookie`很大的过期时间,`Cookie`就能被浏览器保存很长时间;而服务器会定期清理超时的`Session ID`避免出现过大压力;但是`Session`依赖于类似`Session ID`这样的`Cookie`,而`Cookie`对`Session ID`过期时间默许为`-1`。所以只要关闭了浏览器,即一次会话结束后,该`Session`就失效了; * **对服务器造成的压力不同**:`Session`是保存在服务器端的,每个用户都产生一个`Session`,假如并发访问的用户十分多,会产生十分多的`Sssion`,耗费大量的内存;而`Cookie`保存在客户端,不太占用服务器的资源; ## 六、HTTP协议的身份认证 * `BASIC`认证(基本认证) * `DIGEST`(摘要认证) * `SSL`客户端认证 * `FormBase`认证(基于表单认证) ### 1.BASIC认证 **BASIC 认证的认证步骤** : * **步骤 1**:当请求的资源需要` BASIC `认证时,服务器会随状态码 `401 Authorization Required`,返回带 `WWW-Authenticate` 首部字段的响应。该字段内包含认证的方式`(BASIC)`及` Request-URI `安全域字符`(realm)`。 * **步骤 2**: 接收到状态码` 401` 的客户端为了通过 `BASIC` 认证, 需要将用户` ID` 及密码发送给服务器。 发送的字符串内容是由用户 `ID` 和密码构成, 两者中间以冒号`(:) `连接后,再经过` Base64` 编码处理。 假设用户` ID` 为 `guest`,密码是` guest`,连接起来就会形成 `guest:guest` 这样的字符串。 然后经过 `Base64` 编码,最后的结果即是`Z3Vlc3Q6Z3Vlc3Q=`。 把这串字符串写入首部字段 `Authorization` 后, 发送请求。 * **步骤 3**: 接收到包含首部字段` Authorization `请求的服务器,会对认证信息的正确性进行验证。 如验证通过, 则返回一条包含 `Request-URI`资源的响应。 ![image-20200318145152607](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/60.png) `BASIC` 认证虽然采用` Base64 `编码方式,但这不是加密处理。不需要任何附加信息即可对其解码。换言之,由于明文解码后就是用户 `ID`和密码,在` HTTP` 等非加密通信的线路上进行 `BASIC` 认证的过程中,如果被人窃听,被盗的可能性极高。 因此并不常用。 ### 2.DIGEST 认证 为弥补·`BASIC`认证存在的弱点, 从 `HTTP/1.1` 起就有了 `DIGEST` 认证。` DIGEST` 认证同样使用质询 / 响应的方式 `(challenge/response)`,但不会像 `BASIC` 认证那样直接发送明文密码。 所谓质询响应方式是指, 一开始一方会先发送认证要求给另一方, 接着使用从另一方那接收到的**质询码**计算生成**响应码**。 最后将响应码返回给对方进行认证的方式。 ![image-20200318150407496](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/61.png) 因为发送给对方的只是响应摘要及由质询码产生的计算结果,所以比起 `BASIC` 认证,密码泄露的可能性就降低了。 **DIGEST 认证的认证步骤: ** * **步骤 1**:请求需认证的资源时,服务器会随着状态码 `401:Authorization Required`,返 回带 `WWW-Authenticate `首部字段的响应。该字段内包含质问响应方式认证所需的临时质询码(随机数,`nonce`) 。 首部字段` WWW-Authenticate` 内必须包含 `realm` 和 `nonce` 这两个字段的信息。客户端就是依靠向服务器回送这两个值进行认证的。 `nonce `是一种每次随返回的 `401` 响应生成的任意随机字符串。该字符串通常推荐由 `Base64 `编码的十六进制数的组成形式,但实际内容依赖服务器的具体实现。 * **步骤 2**: 接收到 `401 `状态码的客户端,返回的响应中包含 `DIGEST `认证必须的首部字段` Authorization` 信息。 首部字段` Authorization` 内必须包含` username`、 `realm`、` nonce`、 `uri` 和r`esponse `的字段信息。其中,`realm `和 `nonce `就是之前从服务器接收到的响应中的字段。 * **步骤 3**: 接收到包含首部字段 `Authorization` 请求的服务器,会确认认证信息的正确性。 认证通过后则返回包含 `Request-URI `资源的响应。并且这时会在首部字段` Authentication-Info `写入一些认证成功的相关信息。 ![image-20200318151408496](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/62.png) `DIGEST `认证提供了高于` BASIC `认证的安全等级,但是和 `HTTPS `的客户端认证相比仍旧很弱。 `DIGEST `认证提供防止密码被窃听的保护机制,但并不存在防止用户伪装的保护机制 。因此使用范围不大。 ### 3.SSL 客户端认证 从使用用户` ID `和密码的认证方式方面来讲,只要二者的内容正确即可认证是本人的行为。但如果用户 `ID `和密码被盗,就很有可能第三者冒充。利用` SSL`客户端认证则可以避免该情况的发生。 `SSL`客户端认证是借由 `HTTPS` 的客户端证书完成认证的方式。凭借客户端证书认证,服务器可确认访问是否来自已登录的客户端。 **SSL 客户端认证的认证步骤 :** 为达到` SSL`客户端认证的目的 需要事先将客户端证书分发给客户端,且客户端必须安装此证书。 * **步骤 1**:接收到需要认证资源的请求,服务器会发送 `Certificate Request` 报文,要求客户端提供客户端证书。 * **步骤 2**:用户选择将发送的客户端证书后,客户端会把客户端证书信息以 `Client Certificate `报文方式发送给服务器。 * **步骤 3**: 服务器验证客户端证书验证通过后方可领取证书内客户端的`165`公开密钥, 然后开始` HTTPS `加密通信。 **SSL 客户端认证采用双因素认证 :** * 在多数情况下,`SSL`客户端认证不会仅依靠证书完成认证,一般会和**基于表单认证**组合形成一种双因素认证`(Two-factorauthentication) `来使用。 * 换言之,第一个认证因素的` SSL`客户端证书用来认证客户端计算机,另一个认证因素的密码则用来确定这是用户本人的行为。 * 使用 `SSL`客户端认证需要用到客户端证书。而客户端证书需要支付一定费用才能使用。 ### 4.基于表单认证 * 基于表单的认证方法并不是在`HTTP`协议中定义的; * 使用由`Web`应用程序各自实现基于表单的认证方式; * 通过`Cookie`和`Session`的方式来保持用户的状态(具体见上); 也就是常见的登录: ![image-20200318154207699](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/64.png) 输入已事先登录的用户` ID`(通常是任意字符串或邮件地址) 和密码等登录信息后,发送给` Web `应用程序,基于认证结果来决定认证是否成功。 ## 七、HTTP的长连接与短连接 `HTTP`协议是基于请求/响应模式的,因此只要服务端给了响应,本次`HTTP`请求就结束了;`HTTP`的长连接和短连接本质上是`TCP`的**长连接**和**短连接**; ### 1.短连接 完成一次通信之后,客户端主动断开TCP连接; `HTTP/1.0`中,默认使用的是**短连接**。也就是说,浏览器和服务器每进行一次`HTTP`操作,就建立一次连接(三次握手),结束就中断(四次挥手); ### 2.长连接 完成一次通信之后,客户端不主动断开 `TCP`连接,而是复用该`TCP`连接; `HTTP/1.1`起,默认使用**长连接**,用以保持连接特性。此时通用首部字段中的`Connection`字段值为:`Keep-Alive`; 长连接适用于频繁地传输数据的客户端和服务器,为了防止过多的TCP连接影响服务器性能,需要对长时间不用的连接进行释放; ## 八、代理、网关与隧道 `HTTP `通信时,除客户端和服务器以外,还有一些用于通信数据转发的应用程序,例如代理、网关和隧道。它们可以配合服务器工作。 这些应用程序和服务器可以将请求转发给通信线路上的下一站服务器,并且能接收从那台服务器发送的响应再转发给客户端。 ### 1.代理 **代理服务器:** 代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端“**中间人**”的角色,接收由客户端发送的请求并转发给服务器,同时也接收服务器返回的响应并转发给客户端。 ![image-20200318162610556](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/65.png) 代理服务器的基本行为就是接收客户端发送的请求后转发给其他服务器。代理不改变请求` URI`,会直接发送给前方持有资源的目标服务器。 持有资源实体的服务器被称为源服务器,从源服务器返回的响应经过代理服务器后再传给客户端。 ![image-20200318162711944](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/66.png) > 每次通过代理服务器转发请求或响应时,会追加写入 `Via` 首部信息。 **使用代理服务器的理由:** 利用缓存技术(稍后讲解)减少网络带宽的流量,组织内部针对特定网站的访问控制(墙),以获取访问日志为主要目的,等等。 ![image-20200318163146824](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/67.png) **代理使用方法:** 代理有多种使用方法,按两种基准分类。一种是是否使用缓存,另一种是是否会修改报文。 * **缓存代理 ** 代理转发响应时,缓存代理(`Caching Proxy`)会预先将资源的副本(缓存)保存在代理服务器上。当代理再次接收到对相同资源的请求时,就可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回。 * **透明代理 ** 转发请求或响应时,不对报文做任何加工的代理类型被称为**透明代理**(`Transparent Proxy`)。反之,对报文内容进行加工的代理被称为**非透明代理**。 ### 2.网关 网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。有时客户端可能都不会察觉,自己的通信目标是一个**网关**。 ![image-20200318163648918](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/68.png) 网关的工作机制和代理十分相似。但是`Web`网关在一侧使用`HTTP`协议,在另一侧使用另一种协议(比如`FTP`、`SMTP`)。 * (`HTTP/`)服务器端网关:通过`HTTP`协议与客户端对话,通过其他协议与服务器通信; * (`/HTTP`)客户端网关:通过其他协议与客户端对话,通过`HTTP`协议与服务器通信; **常见的网关类型:** * (`HTTP/`*)服务器端`Web`网关; * (`HTTP/HTTPS`)服务器端安全网关:即客户端用`HTTP`与网关通信,网关用`HTTPS`与服务器通信; * (`HTTPs/HTTP`)客户端安全加速器网关:即客户端用`HTTPs`与网关通信,网关用`HTTP`与服务器通信; 也就是**安全网关**,将通过网关的不安全的`HTTP`转换为安全的`HTTPS`; * 资源网关:客户端通过HTTP连接到应用程序的服务器,服务器并不回送文件,而是将请求通过网关API发送给运行在服务器上的应用程序,应用程序将请求资源会送给客户端。这样的客户端可能是一些网络摄像头,电子识别系统等; 利用网关能提高通信的**安全性**,因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。比如,网关可以连接数据库,使用`SQL`语句查询数据。另外,在` Web` 购物网站上进行信用卡结算时,网关可以和信用卡结算系统联动。 ### 3.隧道 隧道可按要求建立起一条与其他服务器的通信线路,届时使用` SSL`等加密手段进行通信。隧道的目的是确保客户端能与服务器进行安全的通信。 隧道本身不会去解析` HTTP` 请求。也就是说,请求保持原样中转给之后的服务器。隧道会在通信双方断开连接时结束。 ![image-20200318165852154](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/69.png) > 通过隧道的传输,可以和远距离的服务器安全通信。隧道本身是透明的,客户端不用在意隧道的存在。 ## 九、HTTP缓存 缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。 缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。 ![image-20200318170530364](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/70.png) ![image-20200318170549956](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/71.png) 缓存服务器的优势在于利用缓存可避免多次从源服务器转发资源。因此客户端可就近从缓存服务器上获取资源, 而源服务器也不必多次处理相同的请求了。 ### 1.缓存的有效期限 即便缓存服务器内有缓存,也不能保证每次都会返回对同资源的请求。因为这关系到被缓存资源的有效性问题。 当遇上源服务器上的资源更新时,如果还是使用不变的缓存,那就会演变成返回更新前的“旧”资源了。 即使存在缓存,也会因为客户端的要求、缓存的有效期等因素,向源服务器确认资源的有效性。若判断缓存失效, 缓存服务器将会再次从源服务器上获取“新”资源。 ![image-20200318170746847](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/72.png) ### 2.客户端的缓存 缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。以`Internet Explorer` 程序为例,把客户端缓存称为临时网络文件(`Temporary Internet File`); 浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取; ![image-20200318170932065](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/73.png) 另外,和缓存服务器相同的一点是, 当判定缓存过期后, 会向源服务器确认资源的有效性。若判断浏览器缓存失效,浏览器会再次请求新资源。 ## 十、HTTP缓存的工作方式(强制缓存与协商缓存) ### 1.场景一 让服务器与浏览器约定一个文件过期时间——`Expires` ![image-20200318180301511](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/74.png) 在`Expires`没有过期的情况下,客户端(浏览器)发出请求时,直接使用`HTTP`本地缓存并返回状态码`200`,这种`HTTP`工作方式称为**强制缓存**; ### 2.场景二 让服务器与浏览器在约定文件过期时间`Expires`的基础上,再加一个文件最新修改时间的对比——`Last-Modified`与`if-Modified-Since` ![image-20200318180227578](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/75.png) * **情况1**:如果`Expires`没有过期,浏览器直接使用`HTTP`本地缓存,即采用**强制缓存**; * **情况2**:如果`Expires`过期了,那么浏览器在请求服务器的时候,就带上了文件最新修改时间,这个字段是在请求头里面加上了`If-Modified-Since`字段,其实该字段的值就是上次请求时服务器返回的`Last-Modified`字段的值;服务器会把请求头里文件的最新修改时间`If-Modified-Since`的值与服务器上的文件最新修改时间`Last-Modified`的值进行比较: * 如果`If-Modified-Since` **不等于**`Last-Modified`,说明浏览器缓存的资源(`f.js`)发生改变,服务器就会去查找最新的`f.js`,同时再次返回`Expires`、`f.js`、`Last-Modified`,返回的状态码为`200`; * 如果`If-Modified-Since` **等于**`Last-Modified`,说明浏览器缓存的资源(`f.js`)没有发生改变,浏览器可以继续使用`HTTP`本地缓存,此时服务器返回状态码`304`;这种方式称为**协商缓存** ### 3.场景三 让服务器在过期时间`Expires`+`Last-Modified`的基础上,增加一个文件唯一标识`Etag`与`If-None-Match`配成一对使用;除此之外,`Expires`不稳定,再加入一个`Max-age`来加以替代(`Max-age`优先级更高); ![image-20200318185030563](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/76.png) * 在60s内,浏览器不再向服务器发起请求,直接使用本地缓存这与`Expires`相似。 * 60s后:浏览器带上`If-Modified-Since`和`If-None-Match`(也就是上次服务器返回的`Etag`值)发起请求,服务器会对比`If-None-Match`与服务器端的`Etag`值,这时即使浏览器也提供了`If-Modified-Since`也不会再与`Last-Modified`进行对比,因为`Etag`的优先级比`Last-Modified`高(更精准); * 如果`If-None-Match`**不等于**`Etag`,说明`f.js`文件已被修改,服务器就会返回最新的`f.js`和全新的`Etag`与`Max-age`(比如`60`),当然也会顺便把`Expires`与`Last-Modified`返回(尽管没用);返回的状态码为`200`; * 如果`If-None-Match`**等于**`Etag`,说明`f.js`文件没有被修改,这时服务器返回的状态码为`304`,告诉浏览器继续使用原来的本地缓存。这种方式属于**协商缓存**; **有了`Last-Modified`为什么还要用`Etag`呢?** 你可能会觉得使用`Last-Modified`已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要`Etag`呢?`HTTP1.1`中`Etag`的出现主要是为了解决几个`Last-Modified`比较难解决的问题: * 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新`GET`; * 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说`1s`内修改了`N`次),`If-Modified-Since`能检查到的粒度是`s`级的,这种修改无法判断(比如淘宝每`ms`都会更新数据); * 某些服务器不能精确的得到文件的最后修改时间; 这时,利用`Etag`能够更加准确的控制缓存,因为`Etag`是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符。 `Last-Modified`与`ETag`是可以一起使用的,服务器会优先验证`ETag`,一致的情况下,才会继续比对`Last-Modified`,最后才决定是否返回`304`。 ### 4.强制缓存与协商缓存 **强制缓存:**直接使用`HTTP`本地缓存,此时服务器返回状态码`200`; **协商缓存:**向服务器确认`HTTP`本地缓存的资源是否发生变化,没变化后再使用`HTTP`本地缓存,此时服务器返回状态码`304`;资源发生变化直接返回最新资源,状态码为`200`;可以这样理解凡是返回`304`状态码,都属于**协商缓存**; **强缓存和协商缓存的区别:** | 缓存 | 获取资源形式 | 状态码 | 发送请求到服务器 | | :------: | :----------: | :-----------------: | :----------------------------------: | | 强缓存 | 从缓存读取 | 200(From Cache) | 否,直接从缓存读取 | | 协商缓存 | 从缓存读取 | 304(Not Modified) | 是,通过服务器告知浏览器缓存是否可用 | 请求头`Cache-Control`的值为**no - store**时表示不允许浏览器(客户端)使用缓存,会直接跳到**协商缓存**; ### 5.缓存改进方案 上述的缓存方案存在一个问题:当`Expires`或`Max-age`没有过期时,浏览器无法**主动**确认本地缓存是否发生变化; #### 5.1.md5/hash缓存 通过不缓存`html`,为静态文件添加`MD5`或者`hash`标识,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题;具体过程为:第一次加载静态文件时,某位置指定加载`f-hash1.js`,第二次加载静态文件时同一个位置指定加载`f-hash2.js`,此时浏览器就会重新向服务器请求数据了; #### 5.2.CDN缓存(最常用) `CDN`是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率; 比如可以把`CDN`理解为各个城市的快递分发站点,源服务器看作快递总仓库; **CDN缓存工作方式**: * **第一次缓存:** ![image-20200318194542397](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/77.png) * **后续请求:** ![image-20200318194515210](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/78.png) `CDN`节点会代替服务器处理浏览器的请求,会有几种情况: * 情况一:`CDN`节点缓存的文件还没过期,于是返回`304`给浏览器,浏览器此次请求被拦截(**协商缓存**); * 情况二:`CDN`节点发现自己缓存的文件过期了,为了保险起见自己发送请求给服务器成功拿回了最新的数据,然后再交还给浏览器; 可以发现,`CDN`缓存问题与`HTTP`缓存是一样的。只不过`CDN`缓存不过期浏览器始终被拦截,无法拿到最新的文件;另外的不同点在于`CDN`相当于一个平台可以手动登录更新缓存,这也就变相解决了不能控制`HTTP`本地缓存的问题。 ### 6.浏览器操作对HTTP缓存的影响 | 用户操作 | Expires/Cache-Control | Last-Modified/Etag | | :-----------: | :-------------------: | :----------------: | | 地址栏回车 | 有效 | 有效 | | 页面链接跳转 | 有效 | 有效 | | 新开窗口 | 有效 | 有效 | | 前进、后退 | 有效 | 有效 | | F5刷新 | **无效** | 有效 | | Ctrl + F5刷新 | **无效** | **无效** | 由上表可知:对于`Last-Modified`和`Etag`字段来说,只有在进行`Ctrl + F5`强制刷新时,这两个字段对缓存是否有效的控制才会失效。即强制刷新后,浏览器不会使用本地缓存,而是直接向服务器发起请求。 ## 十一、内容协商机制 指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为**合适**的资源。内容协商会以响应资源的语言,字符集,编码方式等作为判断的基准。 有三种方式: * **客户端驱动** 由客户端发起请求,服务器发送可选项列表,客户端作出选择后在发送第二次请求; * **服务器驱动** 服务器检查客户端的请求头部集并决定提供哪个版本的页面; * **透明协商** 某个中间设备(通常是缓存代理)代表客户端进行协商; ### 1.服务器驱动 服务器驱动内容协商:**请求首部集**; * **Accept**:告知服务器发送何种媒体类型; * **Accept-Language**:告知服务器发送何种语言; * **Accept-Charset**:告知服务器发送何种字符集; * **Accept-Encoding**:告知服务器采用何种编码; 服务器驱动内容协商:**实体首部集**; * **Content-Type** * **Content-Language** * **Content-Type** * **Content-Encoding** 与请求首部集一一对应; ## 十二、断点续传和多线程下载 `HTTP`是通过在`Header`里两个参数实现的,客户端发出请求时对应的是`Range`,服务器端响应时对应的是`Content-Range`,如果续存成功返回`206`,如果文件有变动返回`200`和新文件的内容; #### 1.Range 用于请求头中,指定第一个字节的位置和最后一个字节的位置,格式为: ``` //格式(左开右闭) Range:(unit = first byte pos) - [last byte pos] //示例 Range: bytes=5001-10000 ``` 接收到附带 `Range` 首部字段请求的服务器,会在处理请求之后返回状态码为 `206 Partial Content` 的响应。 无法处理该范围请求时,则会返回状态码 `200 OK` 的响应及全部资源。 **断点续传过程** * `1`.客户端下载一个`1024K`的文件,已经下载了其中的`512K`。 * `2`.网络中断,客户端请求续传,因此需要在`HTTP`头中申明本次需要续传的片段: `Range:bytes`=`512000~`这个头通知服务器端从文件的`512K`位置开始传输文件; * `3`.服务器收到断点续传请求,从文件的`512K`开始传输,并且在`HTTP`头中增加: ``` Content-Range:bytes 512000-/1024000 ``` 并且此时服务端返回的`HTTP`状态码应该是`206 Partial Content`,而不是`200`; ## 十三、HTTPS `HTTPS`使用的是`TSL`协议(`SSL`是`TSL`协议的一种); #### 1.HTTPS的功能 * **内容加密** * 非对称密钥加密:传输公钥时可能被截获并掉包,解决方案:使用第三方机构颁发的证书加密公钥(根据服务器地址等多个信息生成,无法被第三方伪造),浏览器收到后使用证书机构颁发的公钥进行解密(前提是浏览器要信任同一个证书颁发机构)解密结果与用证书生成的规则再生成一个签名对比一致就是真证书; * 对称密钥加密:中间人随意截获 * **身份认证** * 数字证书 * **数据完整性** #### 2.HTTPS的使用成本 `HTTPS`是一个大趋势 * **证书费用以及更新维护** * 证书现在不贵,也有免费的; * **HTTPS降低用户访问速度** * 经过合理的优化(比如`SPDY`)和部署甚至可以比`HTTP1.0`快,不过这也是成本之一就是了; * **消耗CPU资源,需要增加大量机器** * 需要多次计算 #### 3.HTTPS对性能的影响 * **协议交互所增加的网络RTP(往返时延)** * **加解密相关计算的耗时** **网络耗时:** `HTTP`只需要通过`TCP`的三次握手就能建立`HTTP`连接: ![image-20200319092450746](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/79.png) 而`HTTPS`除了`TCP`的三次握手外,甚至还需要耗费额外的`7`个`RTP`进行验证 ![image-20200319092433164](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/80.png) 关于`302`自动跳转,这是因为,比如访问百度,我们输入网址全称而是输入`baidu.com`,所以会自动跳转至`HTTPS`,这本身也需要耗时; 并且跳转后,`URI`不一样了,浏览器要与服务器重新通过三次握手建立`TCP`连接; 之后还要进行`TLS`协商,比如密钥交换算法,对称加密算法,内容一致性校验算法,证书签名算法等等;浏览器获取到证书后,也需要校验证书的有效性,比如证书是否过期,是否撤销等等; 接着,浏览器首先获取证书里的`CA`域名如果该`CA`域名没有命中缓存,浏览器需要解析域名的`DNS`,这个`DNS`解析至少耗费一个`RTP`; `DNS`解析到`IP`之后就要完成三次握手,建立`CA`站点的`TCP`连接,这又耗费一个`RTP`; 再接着浏览器发送`OCSP`请求,获取响应耗费一个`RTP`; > 关于`OCSP`:在线证书状态协议,它是维护服务器和其他网络资源安全性的两种普遍模式之一,另外一个叫做`CRL`证书注销列表;当用户试图访问一个服务器的时候,在线证书状态协议发送一个对于证书状态信息的请求,服务器会回复一个有效、过期、未知的响应;协议规定了服务器和客户端应用程序通信的语法;在线证书协议给了用户到期证书一个宽限期,这样用户就可以在更新证书前的一段时间继续访问服务器,所以这里就需要发起一个对于证书状态的请求,也需要消耗一个`RTP` 最后就是`TLS`完全握手阶段`2`,这个阶段主要进行密钥协商,耗时一个`RTP`;随后进行应用层的`TCP`数据通信。 **计算耗时** * 浏览器计算耗时; * 服务器计算耗时; #### 4.HTTPS常见问题 * `HTTPS`需要安装证书 * 大型网站比如百度,从`HTTP`升级为`HTTPS`比较困难(不能因为升级而降低用户体验这样就本末倒置了) * `HTTPS`并不能解决所有安全问题(比如`XSS`攻击,木马等),只是能更加安全的传输数据 #### 5.影响HTTP网络请求的因素 * **带宽** * **延迟** * 一条连接上只可发送**一个**请求; * 请求只能从**客户端开始**,客户端不可以接收除响应以外的指令; * 请求/响应头部**不经压缩**就发送,每次互相发送**相同**的头部造成的浪费很多; * 非强制压缩发送; ## 十四、WebSocket 可以理解为`WebSocket`是为了让`HTTP`支持长连接而打的一个大补丁; ![image-20200319105842250](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/81.png) `WebSocket`是一个持久化的`HTTP`,而`HTTP`本身是非持久化的如下图所示:(虽然有`Keep-Alive`) ![image-20200319105852095](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/82.png) #### 1.WebSocket的握手 **请求:** ![image-20200319110017779](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/83.png) **响应:** ![image-20200319110157916](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/84.png) `Upgrade`:表示升级为`WebSocket` #### 2.WebSocket的作用 **HTTP的瓶颈** **请求**只能从客户端发起,客户端不可以接收除了**响应**之外的指令;当客户端需要监听服务器上的内容时,在HTTP中有一些优化处理方式,常用的用:**Ajax轮询**,**Long Poll** * **Ajax轮询** 原理为,客户端每隔几秒就发送一次请求,询问服务器到底有没有新消息;若有服务器返回新消息,没有就返回提示信息,如此循环: ![image-20200319111653521](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/85.png) * **Long Poll长轮询** 与**Ajax轮询**原理相似,客户端先发出请求,直到服务器上有新数据返回之前,都不再发送请求,如此循环: ![image-20200319111724771](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/86.png) **缺陷:**两种方式都非常消耗资源,**Ajax轮询**需要服务器有很快地处理**速度**;**Long Poll**需要服务器有很大**容量**; * **异常情况** ![image-20200319111742047](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/87.png) **WebSocket解决上上述问题** 首先使用`HTTP`协议通知服务器升级到`WebSocket`协议,随后在`WebSocket`协议中,服务器端是可以主动推送数据给客户端的,详细过程: ![image-20200319111934039](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/88.png) **WebSocket的特点** 相比于`HTTP`的长连接,`WebSocket`具有以下特点 * 真正的**全双工方式**:服务器可以主动推送,`HTTP`的长连接仍然是客户端主动发起请求的; * 减少**通信量**:不需要重复传输`HTTP Header`等信息; * 持久性连接:只要进行一次`HTTP`连接,两者就能创建持久的`WebSocket`连接; ## 十五、SPDY **SPDY**是`HTTP`的增强,在向下兼容的情况下,在`TLS`层上新增一层会话层`SPDY`,使用这个会话层来实现`SPDY`协议,也就是说现有的服务格式均不用改变吗;**SPDY**是对`HTTP`的一个更好的实现和支持; ![image-20200319120419163](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/89.png) #### 1.HTTP的缺陷 * **单路连接,请求低效:**最大的弊端所在:每个`TCP`连接只能对应一个`HTTP`请求;也就是每个`HTTP`请求只能请求一个资源;浏览器只能通过建立多个连接来解决低效问题。 * **对请求严格的先进先出:**如果中间的某个请求处理时间比较长的话,就会阻塞后面的请求; * **只允许由客户端主动发起请求:**客户端只能接收服务器发出的响应,服务器无法主动推送信息; * **HTTP的头部冗余:**`HTTP`的头在一个会话里是反复传送的,中间的冗余信息比如:`User-Agent`、`Host`的等不需要重复发送的信息也在不断地重复发送,浪费带宽和资源; #### 2.SPDY的改进 所以基于`HTTP`的上述缺陷,**SPDY**进行了以下改进: * **多路复用请求优化**:`SPDY`规定在一个`SPDY`连接内可以有无限个并行的请求,即多个并发的请求共用一个`TCP`会话;只需要建立一个`TCP`连接就可以传送网页上的所有资源;减少了时延,节省了资源,把`TCP`连接的效率发挥到了最高; * **可以设置请求的优先级**:不必遵守`HTTP`那样的先进先出,而是可以优先传输`CSS`这些更重要的资源,然后再传输网站图标这样不太重要的资源。 * **支持服务器推送功能**:可以实现预加载,比如浏览器请求了`style.css`,服务器就会主动把`style.js`推送给浏览器。这样浏览器请求`style.js`是就可以直接使用本地缓存了;这 与`WebSocket`不同在于,这是**资源**的主动推送; * **SPDY压缩了HTTP头**:舍弃了不必要的`Header`头,可以节省多余数据造成的等待时间,占据的带宽等; * **强制使用SSL传输协议**:客户端全部的请求都要经过`SSL`加密后才能传输; **直观的影响** 对于前端工程师而言,页面优化永远是一个课题。有了`SPDY`的请求优化,可以将请求顺序重新编排,这样很大程度上缓解了页面加载时图片请求带来的影响;减少了`HTTP`的请求; ## 十六、HTTP2.0 上面所讲的`SPDY`后来被谷歌放弃了,转而成为了`HTTP2.0`的前身,基于`SPDY`的核心改造升级开发出了`HTTP2.0`。所以两者有比较多相似的地方: ![image-20200319120435914](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/90.png) #### 1.HTTP2.0性能增强的核心:二进制分帧 在`HTTPS`的基础上新增了二进制分帧层:`Binary Framing`,在该层上`HTTP2.0`会将所有的传输信息分割成更小的消息和帧,并对其采用二进制格式的编码; 如下图所示: ![image-20200319120435914](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/90.5.png) * 请求头信息被封装进了`HEADERS frame`中,请求报文主体被封装进了`DATA frame`中; * `HTTP2.0`的通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息由一个或多个帧组成。这些帧可以乱序发送,然后再根据每个帧首部的流标识符重新组装。 #### 2.HTTP2.0首部压缩 `HTTP2.0`在服务器端和客户端使用**首部表**来跟踪和存储之前发送的键值对,对于相同的数据不再通过每次请求和响应发送,通讯期间几乎不会改变通用的键值对,比如:`Host`、`User-agent`等只需要发送一次;如果这个请求不包含首部,那么首部的开销就变为`0`字节了,此时首部都自动使用之前发送请求的首部; 如下图所示,`Request # 2`中只需要在`HEADERS frame`里发送`:path`这个变化的头部即可,其他头部信息直接沿用`Request #1`的请求头;或者说新增或变化的头部信息会被追加到新的首部表中,如图中的`Request #2`。它在`HTTP2.0`的连接存续期内是始终存在的,由客户端和服务器端共同地渐进地更新; ![image-20200319121457874](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/91.png) #### 3.HTTP2.0多路复用 多路复用这也是继承于`SPDY`协议的,`HTTP2.0`所有的通信都在一个`TCP`连接上完成。`HTTP2.0`把`HTTP`通信的基本单位缩小为一个一个的帧,这些帧对应于逻辑流里面的信息,并行的在同一个`TCP`连接上双向交换; ![image-20200319122435057](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/92.png) `TCP`连接性能的关键在于低延迟。大多数`HTTP`连接的时间都很短,而且是突发性的,而`TCP`只在长时间传输连接,传输大块数据的时候效率是最高的;`HTTP2.0`通过让所有的数据流公用一个`TCP`连接可以更有效地使用`TCP`连接,让高带宽也能真正地服务于`HTTP`的性能提升上。 **但链接多资源的优势** * 可以减少**服务器建立大量链接的压力**,内存占用更少,连接吞吐量变大了。 * 由于`TCP`连接减少而使**网络拥塞状况**得以改观; * 慢启动时间减少,**拥塞**和**丢包**恢复速度更快; 也就是说,资源合并减少请求的方式,对于`HTTP2.0`来说是没有效果,只会开发者无用的工作量而已。所以当`HTTP2.0`普及之后,像雪碧图呀,文件合并等就没有多大意义了。 #### 4.并行双向字节流的请求和响应 ![image-20200319130500653](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/93.png) 简单点说就是可以**乱序发送**,在`HTTP2.0`上客户端和服务器可以把`HTTP`数据的消息分解为互不依赖的数据帧,然后乱序发送,最后在接收端把这些乱序帧重新组合起来。如图所示,同一个连接有多个不同方向的数据流在传输,所以客户端可以一边乱序地发送数据帧,也可以接收服务器的响应;服务器端也是如此都是双向的。 所以:把`HTTP`消息分解为独立的帧交错发送,然后在另一端重新组装是`HTTP2.0`一项很重要的增强; 这一特性会发生连锁反应带来巨大的性能提升: * 并行交错地发送**请求**,请求之间**互不影响**; * 并行交错地发送**响应**,响应之间**互不干扰**; * 只是用一个连接即可**并行发送**多个请求和响应; * 消除不必要的延迟,减少页面加载的时间; #### 5.请求优先级 `HTTP2.0`的这一特性也是继承于`SPDY`,服务器处理不同的流采取不同的优先策略; * 高优先级的流都应该优先发送; * 优先级不是绝对的; * 不同优先级混合也是必须的; #### 6.服务器推送 毕竟`HTTP2.0`的核心是从`SPDY`的基础上衍生而来的;服务器可以对客户端的一个请求发送多个响应,即除了对最初请求的响应之外服务器还可以额外向服务器推送其他资源,而无需客户端明确请求;如图所示:客户端请求了`html`文件,服务器就会把`js`与`css`文件推送给客户端: ![image-20200319132715028](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/94.png) ## 十七、WebDAV协议 `WebDAV`(`Web-based Distributed Authoring and Versioning`,基于万维网的分布式创作和版本控制)是一个可对 `Web` 服务器上的内容直接进行文件复制、编辑等操作的分布式文件系统(可在线修改文件的**网盘**)。 除了创建、删除文件等基本功能,它还具备文件创建者管理、文件编辑过程中禁止其他用户内容覆盖的加锁功能, 以及对文件内容修改的版本控制功能。 ![image-20200319140154332](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/95.png) 使用 `HTTP/1.1` 的 `PUT` 方法和 `DELETE` 方法, 就可以对 `Web `服务器上的文件进行创建和删除操作。 可是出于安全性及便捷性等考虑,一般不使用。 #### 1.WebDAV 内新增的方法及状态码 `WebDAV` 为实现远程文件管理,向 `HTTP/1.1` 中追加了以下这些方法。 | 方法 | 用途 | | :-------: | :------------: | | PROPFIND | 获取属性 | | PROPPATCH | 修改属性 | | MKCOL | 创建集合 | | COPY | 复制资源及属性 | | MOVE | 移动资源 | | LOCK | 资源加锁 | | UNLOCK | 资源解锁 | 新增状态码: | 状态码 | 含义 | | :---------------------: | :----------------------------------------------: | | 102 Processing | 可正常处理请求,但目前是处理中状态 | | 207 Multi-Status | 存在多种状态 | | 422 UnprocessibleEntity | 格式正确,内容有误 | | 423 Locked | 资源已被加锁 | | 424 FailedDependency | 处理与某请求关联的请求失败,因此不再维持依赖关系 | | 507 InsufficientStorage | 保存空间不足 | **WebDAV 的请求实例 ** 下面是使用 `PROPFIND` 方法对` http://www.example.com/file` 发起获取属性的请求 : ``` PROPFIND /file HTTP/1.1 Host: www.example.com Content-Type: application/xml; charset="utf-8" Content-Length: 219 //...请求主体 ``` **WebDAV 的响应实例 ** 下面是针对之前的 `PROPFIND` 方法, 返回`http://www.example.com/file `的属性的响应。 ``` HTTP/1.1 207 Multi-Status Content-Type: application/xml; charset="utf-8" Content-Length: 831 //...响应主体 ``` 不过可以使用`FTP`替代它; ## 十八、HTTP3.0 ![image-20200319142842312](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/96.png) #### 1.HTTP2.0的问题 * **队头阻塞**:由于只建立一个`TCP`连接,一旦出现某次传输出现丢包,就要等待重传,严重阻碍了其他数据的传输; * **建立连接的握手延迟大**:`HTTPS`和`HTTP2.0`除了建立`TCP`握手之外,还要建立`TSL`安全传输,这就出现了两次握手延迟;对于短连接来说,影响无法被移除,这些都是`TCP`的历史遗留问题; #### 2.QUIC的特性 * **0 RTP**:两层意思,建立`UDP`连接和建立`TSL`安全连接大多数情况只需要`0 RTP`; ![image-20200319143544308](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/97.png) * **没有队头阻塞的多路复用** 当`TCP`连接中传输的数据流`stream2`中出现丢包时,在发送端没有重传丢失的包之前跟在`stream2`后面的`stream3/4`就被阻塞住了; ![image-20200319143715846](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/98.png) 然而`UDP`连接中,数据流彼此间没有依赖关系,即使`stream2`出现丢包,也不影响其他`stream`数据的传输; ![image-20200319144040196](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/99.png) * **前向纠错**(`Front Error Collection`) 每个数据包除了它本身的数据之外,还包括了部分其他包的内容,因此少量的丢包可以通过其他包的冗余数据直接组装,而无需重传;这种方法虽然牺牲了每个数据包可发送数据的上限,但是减少了因为丢包导致的数据重传(更浪费时间);如果丢失的包过多,就只能通过重传来解决。 **QUIC**融合了`UDP`协议的速度性能和`TCP`的安全和可靠,大大优化了互联网传输数据的体验。 #### 3.HTTP协议总结 * `HTTP1.0/1.1`:有**连接无法复用**、**队头阻塞**、**协议开销大**和**安全因素**等多个缺点; * `HTTP2.0`:通过**多路复用**、**二进制流**、**头部压缩**等技术极大地提升了性能,但是还是存在问题; * `HTTP3.0`:`QUIC`是基于`UDP`实现的,是`HTTP3.0`的底层支持协议。该协议基于`UDP`又吸收了`TCP`的精华,实现了既快又可靠的连接; ## 十九、Web安全 ### 1.概述 **日常生活中的”安全“** * 为什么登录的时候经常要求我们输入一个验证码? * 在一个网站上长时间没有操作,为什么`Session`会失效? #### 1.1.WASC的定义 全程`Web Application Security Consortium`:是一个由安全专家、行业顾问和诸多组织的代表组成的国际团体,负责为`WWW`(万维网)制定广为人知的**应用安全标准**。 #### 1.2.六类Web应用安全威胁 | 名称 | 中文名 | 作用 | | :--------------------: | :--------: | :----------------------------------------------------------: | | Authentication | 验证 | 用来确认某用户、服务或是应用身份的攻击手段 | | Authorization | 授权 | 用来决定是否某用户、服务或是应用具有执行请求动作必要权限的攻击手段 | | Client-Side-Attacks | 客户侧攻击 | 用来扰乱或是探测`Web`站点用户的攻击手段 | | Command Execution | 命令执行 | 在`Web`站点上执行远程命令的攻击手段(比如`SQL`注入) | | Information Disclosure | 信息泄露 | 用来获取`Web`站点具体系统信息的攻击手段 | | Logical Attacks | 逻辑性攻击 | 用来扰乱或是探测`Web`应用逻辑流程的攻击手段 | #### 1.3.OWASP的定义 全称`Open Web Application Security Project`,该组织致力于发现和解决不安全`Web`应用的根本原因;它们最重要的项目之一是**Web应用的十大安全隐患** 总结了目前`Web`应用最常受到的十种攻击手段,并且按照攻击发生的概率进行了排序(以下为`2017`年的数据): | 排名 | 漏洞种类 | 详情 | | :--: | :--------------------: | :----------------------------------------------------------: | | A1 | 注入 | 将不受信任的数据作为命令或查询的一部分发送到解析器时,会产生注入:`SQL`注入、`NoSQL`注入、`OS`注入和`LDAP`注入缺陷。 | | A2 | 失效的身份认证 | 通过错误的使用应用程序的身份认证和会话管理功能,攻击者能够破译密码、密钥或会话令牌 | | A3 | 敏感数据泄露 | 许多`Web`程序和`API`都无法正确保护敏感数据,攻击者可通过窃取或修改未加密的数据来实施信用卡诈骗、身份盗窃等犯罪行为 | | A4 | XML外部实体(XXE) | 许多较早的或配置错误的`XML`处理器评估的`XML`文件中的外部实体引用。攻击者可利用外部实体窃取内部文件、执行远程代码 | | A5 | 失效的访问控制 | 未对通过身份验证的用户实施恰当的访问控制 | | A6 | 安全配置错误 | 安全配置错误是最常见的安全问题,这通常是由于不安全的默认配置、不完整的临时配置、开源云错误等造成 | | A7 | 跨站脚本(XSS) | `XSS`让攻击者能够在受害者的浏览器中执行脚本,并劫持用户会话、破坏网站或将用于重定向到恶意站点 | | A8 | 不完全的反序列化 | 不安全的反序列化会导致远程代码执行 | | A9 | 使用含有已知漏洞的组件 | 组件如库、框架和其他软件模块拥有和应用程序相同的权限 | | A10 | 不足的日志记录和监控 | 不足的日志记录和监控,以及事件响应缺失或无效的集成,使攻击者能够进一步攻击系统、保持持续性、篡改、提取或销毁数据 | ### 2.验证机制 验证机制是`Web`应用程序中最简单的一种**安全机制**,也是防御恶意攻击的**核心机制**; #### 2.1.典型的身份验证模式 ![image-20200319153857741](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/100.png) **验证技术** * 基于**HTML表单**的验证 * 多元机制,如组合密码; * 客户端`SSL`证书 **弱密码** 许多`Web`应用程序没有或很少对用户密码强度进行控制; **暴力破解** 登录功能的公开性会诱使**攻击者**试图**猜测**用户名和密码,从而获得访问应用程序的权力; **暴力破解-安全措施** * **验证码技术**:最常见和有效的应对方式,需要注意几个问题: * **验证码**是否真实有用 * 验证码的**复杂度**:从最开始的数字,到数字字母组合,再到谷歌奇形怪状的字母; * 应对当前的”**打码**“事业盛行:使用专门平台的”**打码**“服务器进行破解;对此出现了点击型的验证码、滑动型的验证码、问答型的验证码等更高级的验证码; * **Cookie和会话检测**:有些应用程序会设置一个**Cookie**,如`failedlogin = 0`;尝试登录失败,递增该值,达到某个上限,检测到这个值并拒绝再次处理登录; * 这样也不安全,只要客户端的`Cookie`在到达服务器端前被截获,就能被篡改; * **双因子认证**:双因子认证的核心是综合`What you know`(**个人密码**)和`What you have`(手机)来达到双重认证效果;(**较安全常用**) ### 3.会话管理机制 * 绝大多数`Web`应用程序中,会话管理机制是一个基本的**安全组件**。会话管理机制在应用程序执行登录功能时尤为重要,因为:它可以在用户通过请求提交它们的证书后,**持续向应用程序保证任何特定用户身份的真实性**; * 由于会话管理机制所发挥的关键作用,它们就成为了针对应用程序的**恶意攻击**的主要目标; * 若攻击者能够**破坏**应用程序的会话管理,他就能轻易避开其实施的验证机制,不需要用户证书即可伪装成其他应用程序用户。 #### 3.1.会话管理存在的漏洞 * **会话令牌生成漏洞**:比如采用常见的算法生成,容易被人猜出算法名称进行反编译破解; * **令牌可预测**:比如隐含序列,事件依赖; * **会话终止攻击**:会话结束后,**Cookie**没有真正意义上被删除,下次验证还有效; * **会话劫持攻击**:比如网络嗅探、`XSS`攻击等方式获取用户的会话令牌; #### 3.2.会话管理漏洞的防御 **令牌传输安全** * 令牌只能通过**HTTPS**传送; * 如果使用`HTTP cookie`传送令牌(大多数情况下)应该将`Cookie`字段标记为`Secure`,以防止用户浏览器通过`HTTP`传送它们; **增加软硬会话过期** * **软会话过期**:它指的是用户在一定的事件内与应用系统没有交互,则**会话过期**也就是我们常说的**Session失效**; * **硬会话过期**:它指的是用户登录到系统中经过一定的事件后,不管用户做什么,该会话都会过期(**网吧上网时间到了,强制下机**); ## 二十、常见的网络攻击 ### 1.SQL注入攻击 #### **1.1.SQL注入原理** * 几乎每个`Web`应用都需要使用**数据库**来保存操作所需要的各种信息; * 所以`Web`程序是经常会建立用户提交数据的`SQL`语句; * 最严重的情况下,攻击者可利用`SQL`注入,读取甚至修改数据库中保存的所有数据; * 用户可以提交一段**数据库查询代码**,根据程序返回结果,获得某些他想得知的数据; 这就是所谓的**SQL Injection**,即`SQL`注入;比如: ![c](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/101.png) 帐户名中输入的`‘or’1 = 1`会被识别为`SQL`操作指令; #### **1.2.SQL注入危害** * **探知数据库**的具体结构,为进一步攻击准备; * **泄露数据**,尤其是机密信息、账户信息等; * **取得更高权限**,用来修改数据甚至是内部结构; #### 1.3.SQL注入防御 **参数化查询** * **参数化查询**是对`SQL`注入根本性的**防御策略**,也叫做预处理语句,在建立一个包含用户输入的`SQL`语句时分为两步: * **指定查询结构,用户输入预留占位符;** * **指定占位符内容;** 比如使用问号`?`当作占位符,这样即使输入了`SQL`语句这样也不会被认为是数据`SQL`的一部分,而是用户输入内容。 **字符串过滤** **使用正则表达式过滤传入的参数** ### 2.跨域脚本攻击(XSS) 跨站脚本攻击(`Cross Site Scripting`),`XSS`(`CSS`已被占用所以叫`XSS`)是一种经常出现在`Web`应用中的计算机安全漏洞; 它允许`Web`用户恶意地将代码植入到提供给其他用户使用的页面中,其他用户在观看网页时,恶意脚本就会执行; #### 2.1.XSS攻击原理 * 这类攻击通常通过注入`HTML`或`JS`等脚本发动攻击; * 攻击成功后,攻击者可以得到私密网页内容和`Cookie`等; * 最近几年`XSS`攻击已成为最流行的攻击方式; #### 2.2.XSS攻击危害 * **盗取各类用户账号**:如机器登录账号、用户网银账号、各类管理员账号; * **控制数据**:包括读取、篡改、添加、删除企业敏感数据的能力; * 盗窃企业重要的具有**商业价值**的资料; * 非法转账; * 强制发送网站挂木马; * 控制受害者机器,让该用户成为"肉机",向其他网站发起攻击; #### 2.3.XSS攻击真实案例 > **Myspace XSS攻击事件** * 2005年,一名叫做`samy`的用户发现了`Myspace`(社交网站)的`XSS`漏洞,他在用户资料页面插入了一些`javascript`脚本; * 如果一个用户查看了他的用户资料,这段脚本就会被执行; * 脚本包括两方面:一是把`Samy`加为好友,二是将上面说的脚本复制到受害者自己的用户资料页面中; * 于是,所有查看受害者用户资料的用户也会成为受害者; * 一个基于存储式`XSS`攻击的蠕虫迅速扩散,几个小时内,`Samy`收到了近百万个好友的申请; * 为此,`Myspace`被迫关站,修复反`XSS`过滤机制并且从所有用户的资料中删除含有恶意脚本的内容; #### 2.4.XSS分类 针对`XSS`的攻击方式不同,可以把`XSS`分为如下三大类: * **反射式XSS** * **存储式XSS** * **基于DOM的XSS** ##### 反射式XSS 也称为**非永久性XSS**,目前最流行的`XSS`攻击;它出现在服务器直接服务器直接使用客户端提交的数据,如`URL`的数据、`HTML`表单中提交的数据,并且没有对数据进行无害化处理;如果提交的数据中含有`HTML`控制字符而没有被正确处理,那么一个简单的`XSS`攻击就会发生。 典型的反射式攻击方式可通过一个邮件或中间网站,诱饵是一个**看起来可信任**的站点的链接,其中包含`XSS`攻击脚本,比如社交群中常发的游戏活动、赌博、美女链接等。如果信任的网站没有正确处理这个脚本,用户点击后就会导致浏览器执行含有恶意攻击的脚本。 ##### 存储式XSS 也称为**永久性XSS**,危害更大。攻击将攻击脚本上传到`Web`服务器上,使得所有访问该页面的用户都面临信息泄露的可能,其中也包括了`Web`服务器的管理员; 存储式`XSS`多发生在最终显示给其他用户的位置包含: * 个人信息字段,如姓名、地址、电子邮件、电话等; * 文档、上传文件及其他数据的名称; * 提交给应用程序管理员的反馈或问题; * 向其他应用程序用户传送的消息、注释、问题等; * 在用户之间共享的上传文件内容; **典型的存储式XSS攻击过程** * 我拥有一个`Web`站点,该站点允许用户发布信息/浏览已发布信息; * 你注意到我的站点具有存储式的`XSS`漏洞; * 于是你发布一个热点信息,利用该漏洞获取用户信息,吸引其他用户纷纷阅读; * 任何其他人浏览该信息,其绘画`Cookies`或其他信息都会被你盗走; ##### 基于DOM的XSS攻击 反射式`XSS`攻击和存储式`XSS`攻击都是通过服务器提取用户提交的数据,并且以不安全的方式将其返回给用户;基于`DOM`的攻击仅仅通过`JavaScript`的方式执行; 也就是说这种攻击常发生在应用程序每次返回相同的静态页面(`HTML`文件),并通过客户端的`js`文件动态生成信息,并不会与服务器交互获取该`js`文件的时候; #### 2.5.XSS攻击载荷 **会话令牌** * `XSS`攻击对普遍的方式; * 截取一名受害者的会话令牌(`Token`),劫持他的会话,进而作为受害者的身份来使用应用程序,执行任意操作并占有该用户的账号; **虚拟置换** * 这种攻击需要在一个`Web`应用程序页面注入恶意数据,从而向应用程序的用户传送误导性信息; * 包括简单的向站点注入`HTML`,或者使用脚本注入精心设计的内容; 比如在淘宝的搜索结果页面中注入一个链接,受害者点击后跳转到一个和淘宝很像的钓鱼网页,登录时帐户信息就被泄露了; * 攻击者实际上没有修改保存在服务器上的内容,而是利用程序处理并显示用户提交的输入方面的缺陷实现置换; **注入木马** * 在一个明显的攻击中,攻击者注入的功能向用户显示一个木马登录表单,要求他们像攻击者控制的服务器提交他们自己的证书。 #### 2.6.XSS防御措施 ##### 输入验证 * 在输入的过程中,如果应用程序有向后端提交处理的数据,应**对这些数据进行严格的确认**; * 比如:数据不能太长; * 数据仅包含某组合法字符; * **数据与一个特殊的正则表达式匹配**(比如手机号); * 根据应用程序希望在每个字段中收到的数据类型,尽可能限制性地对姓名、电子邮件地址、账号等应用不同的确认规则; ##### 输出编码 * 如果应用程序将某位用户或第三方提交的数据复制到它的响应中,那么应用程序应对这些数据进行`HTML`编码,以净化可能的恶意字符; * `HTML`编码指用对应的`HTML`实体替代字面量字符。这样做可确保浏览器安全处理可能为恶意的字符,把它们当作`HTML`文档的内容而非结构处理; * 经常造成问题的字符的`HTML`编码: * `”` -> `"` * `'` -> `'` * `<` -> `<` * `>` -> `>` * `/` -> `x2F` 应用程序之所以结合使用**输入确认**(次要)与**输出净化**(首要),原因在于这种方法能够提供两层防御:如果其中一层被攻破,另一层还能提供一些保护; ### 3.CSRF攻击 `CSRF`(`Cross-site Request Forgery`)**跨站请求伪造**,也被称为`One Click Attack`或者`Session riding`通常缩写为`CSRF`或者`XSRF`,是一种对**网站的恶意利用**; 尽管听起来像跨站脚本(`XSS`),但它与`XSS`非常不同,并且攻击方式几乎相左; #### 3.1.CSRF攻击原理 * `XSS`利用站点内的**信任用户**(受害者),而`CSRF`通过伪装来自受信任用户的请求来利用**受信用的网站**; * 通过社会学的手段(如通过电子邮件发送一个链接)来蛊惑受害者进行一些敏感性的操作,如修改密码、修改`E-mail`、转账等,而受害者还不知道他已经中招; #### 3.2.CSRF攻击危害 * `CSRF`的**破坏力**依赖于**受害者**的**权限**; * 如果受害者只是个**普通用户**,则一个成功的`CSRF`攻击会危害用户的数据以及一些功能; * 如果受害者具有**管理员权限**,则一个成功的`CSRF`攻击甚至会威胁到整个网站的安全; * 与`XSS`攻击相比,`CSRF`攻击往往不太流行,因此对其进行防范的资源也相当稀少,和难以防范; * 故被认为比`XSS`更具危险性,所以`CSRF`在业内有个响当当的名字——**沉睡的巨人** #### 3.3.CSRF攻击的特点 - 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。 - 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。 - 整个过程攻击者**并不能**获取到受害者的登录凭证,仅仅是“冒用”。 - 跨站请求可以用各种方式:图片`URL`、超链接、`CORS`、`Form`提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。 `CSRF`通常是**跨域**的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。(比如博客留言) #### 3.4.CSRF攻击的过程 - 受害者登录`a.com`,并保留了登录凭证(`Cookie`); - 攻击者引诱受害者访问了`b.com`; - `b.com` 向` a.com` (服务器)发送了一个请求:`a.com/act=xx`。浏览器会默认携带`a.com`发放的`Cookie`; - `a.com`接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者(`a.com`的用户)自己发送的请求; - `a.com`以受害者的名义执行了`act=xx`; - 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让`a.com`执行了自己定义的操; #### 3.5.CSRF攻击预防 `CSRF`通常从第三方网站发起,被攻击的网站无法防止攻击发生,只能通过增强自己网站针对`CSRF`的防护能力来提升安全性。 上文中讲了`CSRF`的**两个特点**: - `CSRF`(通常)发生在第三方域名。 - `CSRF`攻击者不能获取到`Cookie`等信息,只是使用。 针对这两点,我们可以专门制定防护策略,如下: - **阻止不明外域的访问** - 同源检测 - `Samesite Cookie` - **提交时要求附加本域才能获取的信息** - `CSRF Token` - 双重`Cookie`验证 - 增加确认操作 - 重新认证 ##### 增加确认操作 * 比如转账功能,当用户调用`API`进行转装的时候,弹出一个对话框,例如:你确认转帐`200`元吗?即在浏览器上进行敏感操作时增加**确认操作**,**确保是用户所为**; ##### 重新认证 * 在做一些重要敏感的操作时,要求用户**重新输入密码**进入二次验证,只有正确了才进行操作;这种做法显然更安全,但对于用户来说不是特别友好——毕竟是增加了异一步操作; * 所以**安全和易用性**,有时候不得不做出取舍; ##### 使用Token* `CSRF`的一个特征是,攻击者无法直接窃取到用户的信息(`Cookie`,`Header`,网站内容等),仅仅是冒用`Cookie`中的信息。 而`CSRF`攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个`CSRF`攻击者无法获取到的`Token`。服务器通过校验请求是否携带正确的`Token`,来把正常的请求和攻击的请求区分开,也可以防范`CSRF`的攻击。 **验证过程** * 服务器端:在用户刚登陆的时候,产生一个新的不可预知的`CSRF Token`,并且把此`Token`存放在用户的`session`中。 * 在任何一个需要保护的表单中(转账,该密码),增加一个隐藏的字段来从服务器端获取和存放这个`Token`; * 提交请求的时候,在服务器端检查提交的`Token`与用户`Session`中的`Token`是否一致,如果一致,继续处理请求,不一致或者没有的话,就返回一个错误的信息给用户。 * 在用户退出或者`Session`过期的时候,用户信息(包括`CSRF Token`)从`Session`中移除并且销毁`Session`。 > 参考资料:[大话HTTP协议](https://coding.imooc.com/class/395.html)、《图解HTTP》、[前端安全系列之二:如何防止CSRF攻击?](https://www.cnblogs.com/meituantech/p/9777222.html)
`GET` 请求。 响应报文中包含由 `Content-Range` 指定范围的实体内容。 | #### 3xx:重定向 | 状态码 | 状态码英文名称 | 描述 | | ------ | :---------------: | :----------------------------------------------------------: | | 301 | Moved Permanently | 永久重定向,请求的资源已被永久的移动到新的`URI`,返回信息会包括新的`URI`,浏览器会自动定向到新的`URI`。今后任何新的请求都会使用新的`URI`(比如某的网站域名已更改,访问旧网址会自动跳转到网址) | | 302 | Found | 暂时重定向,与`301`类似。但资源只是临时被移动,客户端应继续使用原有的URI | | 303 | See Other | 该状态码表示由于请求对应的资源存在着另一个` URI`, 应使用 `GET`
方法定向获取请求的资源。与`302`区别在于`303`希望用户使用`GET`访问新的`URI`,而`302`可以使用`POST`访问新的`URI` | | 304 | Not Modified | 该状态码表示客户端发送附带条件时(`If-Match`, `If-ModifiedSince`等), 服务器端允许请求访
问资源, 但未满足附带的条件。 此时返回,`304` 状态码, 不包含任何响应
的主体部分。另一种理解:**所请求的资源没有更改,可以使用缓存** | #### 4xx:客户端错误 | 状态码 | 状态码英文名称 | 描述 | | :----: | :------------: | :----------------------------------------------------------: | | 400 | Bad Request | 客户端请求报文语法错误,服务器无法理解 | | 401 | Unauthorized | 表示发送的请求需要有通过` HTTP `认证(`BASIC` 认证、
`DIGEST `认证) 的认证信息 | | 403 | Forbidden | 服务器理解客户端的请求,但是拒绝执行此请求 | | 404 | Not Found | 服务器无法根据客户端的请求找到资源(网页) | #### 5xx:服务器错误 | 状态码 | 状态码英文名称 | 描述 | | :----: | :-------------------: | :----------------------------------------------------------: | | 500 | Internal Server Error | 服务器端内错误或` Web`
应用存在`bug`或某些临时的故障,导致无法完成请求 | | 502 | Bad Gateway | 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求 | | 503 | Service Unavailable | 表明服务器暂时处于超负载或正在进行停机维护, 现在无法
处理请求 | ## 三、HTTP首部 ### 1.HTTP请求和响应报文 #### 1.1HTTP请求报文 ![image-20200317202609927](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/2.png) ![image-20200318103054848](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/3.png) #### 1.2.HTTP响应报文 ![image-20200317202637972](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/4.png) ![image-20200318103225790](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/5.png) 可见HTTP报文一共有**四种**首部字段(请求头):**请求首部字段、响应首部字段、通用首部字段、实体首部字段;** #### 1.3.示例 在`chrome`的开发者调试工具当中,从请求报文和响应报文分各抽出了一部分,形成了三部分: **General:** ![image-20200318105143441](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/6.png) **Request Headers:** ![image-20200318105327277](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/7.png) **Response Headers:** ![image-20200318105410254](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/8.png) ### 2.请求首部字段 ![image-20200317203914289](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/9.png) #### 2.1.Accept 作用:**浏览器端可以接受的媒体类型;** ![image-20200318095255629](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/10.png) 若想要给显示的媒体类型增加优先级, 则使用 `q`来额外表示权重值,用分号`(;)`进行分隔。权重值` q` 的范围是` 0~1`(可精确到小数点后` 3` 位) ,且` 1 `为最大值。不指定权重` q` 值时,默认权重为 `q=1.0`。 当服务器提供多种内容时,将会首先返回权重值**最高**的媒体类型。 #### 2.2.Accept-Charset 作用:用来通知服务器用户代理(浏览器)支持的字符集及字符集的相对优先顺序。 ![image-20200318095604225](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/11.png) 图Accept-Charset字段中的值: ``` Accept-Charset: iso-8859-5, unicode-1-1;q=0.8 ``` 中的`unicode-1-1;q=0.8`是一个整体,表示unicode编码优先级为0.8,小于默认的iso编码优先级(默认q=1);**不要以为分号(;)为分割符,其实逗号(,)才是分割符** #### 2.3.Accept-Encoding 作用:用来告知服务器用户代理支持的内容编码及内容编码的**优先级顺序**。 可一次性指定**多种**内容编码。 ![image-20200318095930260](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/12.png) ``` Accept-Encoding: gzip, deflate ``` 常见的编码方式有:**gzip**、**compress**、**deflate**、**identity**。 #### 2.4.Accept-Language 作用:用来告知服务器浏览器能够接收的语言 ,以及相对优先级。 ![image-20200318100341589](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/13.png) ``` Accept-Language: zh-cn,zh;q=0.7,en-us,en;q=0.3 ``` 上述值表示:优先请求中文版,其次是英文版; #### 2.5.Host ![image-20200317210815624](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/14.png) ``` Host: www.hackr.jp ``` 若服务器未设定主机名,`Host`为空值即可。 #### 2.6.If-Match ![image-20200317211022050](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/15.png) 形如`If--xxx`这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。 ![image-20200317211036278](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/16.png) 上图表示:只有当`If-Match`的字段值跟`Etag`值匹配一致时,服务器才会接收请求。 #### 2.7.If-Modified-Since ![image-20200317211327966](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/17.png) 上图表示:如果在`If-Modified-Since`字段指定的日期时间后,资源发生了更新,服务器会接收请求,此时返回状态码`200`;否则会拒绝接收请求返回`304`(因为资源都没更新过,不需要重新请求),与响应头`Last-Modified`是一对; #### 2.8.If-None-Match 只有在 `If-None-Match` 的字段值与 `ETag `值不一致时, 可处理该请求。 与 `If-Match` 首部字段的作用相反; ![image-20200317211800953](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/18.png) #### 2.9.If-Range 首部字段 `If-Range` 属于附带条件之一。 它告知服务器若指定的 `If-Range` 字段值(`ETag` 值或者时间) 和请求资源的 `ETag` 值或时间相一致时, 则作为范围请求处理。 反之, 则返回全体资源。 ![image-20200317212055861](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/19.png) 下面我们思考一下不使用首部字段` If-Range` 发送请求的情况。 服务器端的资源如果更新, 那客户端持有资源中的一部分也会随之无效,当然,范围请求作为前提是无效的。这时,服务器会暂且以状态码 `412:Precondition Failed `作为响应返回, 其目的是催促客户端再次发送请求。这样一来,与使用首部字段 `If-Range `比起来,就需要花费两倍的功夫。 ![image-20200317212159337](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/20.png) #### 2.10.Referrer 作用:告诉服务器我是从哪个页面的链接过来的,服务器籍此可以获得一些信息用于处理; ![image-20200318101839032](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/21.png) ``` Referer: http://www.hackr.jp/index.htm ``` #### 2.11.User-Agent 作用:告诉HTTP服务器,客户端使用的操作系统和浏览器的名称和版本; ![image-20200318102046185](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/22.png) ``` User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/2010010 ``` 很多时候我们会通过该字段来判断浏览器类型,从而进行不同的兼容性设计。 ### 3.响应首部字段 ![image-20200317203931940](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/23.png) ![image-20200317212421283](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/24.png) #### 3.1.Age 首部字段 `Age` 能告知客户端,源服务器在多久前创建了响应。字段值的单位为秒。 ![image-20200317212504499](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/25.png) #### 3.2.ETag 首部字段` ETag` 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 `ETag`值。 另外, 当资源更新时,`ETag` 值也需要更新。生成 `ETag` 值时,并没有统一的算法规则,而仅仅是由服务器来分配。 ![image-20200317212602438](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/26.png) 与响应头`If-None-Match`是一对; #### 3.3.Location 使用首部字段` Location` 可以将响应接收方引导至某个与请求 `URI` 位置不同的资源。 基本上,该字段会配合 `3xx : Redirection` 的响应, 提供重定向的`URI`。 ### 4.通用首部字段 ![image-20200317203943920](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/27.png) #### 4.1.Cache-Control **a.请求首部中Cache-Control的指令:** ![image-20200317204206171](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/28.png) **b.响应首部中Cache-Control的指令:** ![image-20200317204635351](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/29.png) **Cache-Control各指令详解:** * **public指令:**客户端和代理服务器(`CDN`)可以缓存; * **Private指令:**只有客户端可以缓存; ![image-20200317204824663](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/30.png) * **no-store指令:**真正意义上的所有内容都不缓存(**协商缓存**); * **no-cache指令:**正确来说该指令还是会使用缓存,只不过使用前要确认其新鲜程度(**协商缓存**); ![image-20200317204854401](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/31.png) * **s-maxage = x指令 **:代理服务器请求源站缓存后的X秒内不再发出请求,只对`CDN`缓存(`CDN`指的是拥有源服务器资源的多个分布式服务器)有效; ``` Cache-Control: s-maxage=604800 //(单位 : 秒) ``` 此外,当使用 `s-maxage` 指令后,则直接忽略对 `Expires` 首部字段及`max-age` 指令的处理。 即优先级为:**`S-maxage` > `Max-age` > `Expires`** * **Max-age = x指令:**请求缓存后的X秒内不再发起请求。 ``` Cache-Control: max-age=604800 //(单位: 秒) ``` ![image-20200317204940262](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/32.png) 当**客户端**发送的请求中包含` max-age `指令时: 如果判定指定的时间比缓存资源的缓存时间数值**更大**,那么客户端就接收缓存的资源。另外,当指定 `max-age` 值为 `0`(指定时间**更小**),那么缓存服务器通常需要将请求转发给源服务器。 当**服务器**返回的响应中包含 `max-age` 指令时,缓存服务器将不对资源的有效性再作确认,而直接把 `max-age` 数值作为保存为缓存的资源的最长时效。 应用 `HTTP/1.1` 版本的缓存服务器遇到同时存在 `Expires` 首部字段的情况时,会优先处理 `max-age` 指令,而**忽略**掉 `Expires` 首部字段。 #### 4.2.Connection 有两个作用: * **控制不再转发给代理的首部字段:** ![image-20200317210000299](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/33.png) 如图中,`Connection`的值为`Upgrade`表示不将`Upgrade`这个首部发给代理; * **管理持久连接:** a.当`Connection : close` 时: ![image-20200317210148420](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/34.png) 代表一个`Request`完成后,客户端和服务器之间用于传输`HTTP`数据的`TCP`连接会关闭(四次挥手)。当客户端再次发送`Request`,需要重新建立`TCP`连接(三次握手)。 b.当`Connection:Keep-Alive` 时: ![image-20200317210232981](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/35.png) 此时,当一个网页打开完成后(已经建立TCP连接),客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器,会继续使用这条已经建立的连接; #### 4.3.Via 使用首部字段Via是为了追踪客户端与服务器之间的请求和响应报文的传输路径: ![image-20200317210436541](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/36.png) ### 5.实体首部字段 ![image-20200317203957114](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/37.png) 实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息。 ![image-20200317213108376](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/38.png) #### 5.1.Content-Type 作用:说明报文内对象的媒体类型; ``` Content-Type: text/html; charset=UTF-8 ``` #### 5.2.Expires ![image-20200317213143041](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/39.png) 首部字段 `Expires` 会将资源失效的日期告知客户端。**缓存服务器**(代理服务器)在接收到含有首部字段 `Expires `的响应后,会以缓存来应答请求,在`Expires` 字段值指定的时间之前,响应的副本会一直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。 源服务器不希望缓存服务器对资源缓存时, 最好在 `Expires` 字段内写入与首部字段 `Date` 相同的时间值。 但是,当首部字段` Cache-Control` 有指定 `max-age` 指令时,比起首部字段 `Expires`,会优先处理 `max-age `指令。 #### 5.3.Last-Modified ![image-20200317213437706](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/40.png) 首部字段 `Last-Modified` 指明资源最终修改的时间。 与请求头`If-Modified-Since`是一对; ``` Last-Modeified: Wed, 23 May 2012 09:59:55 GMT ``` ### 6.为 Cookie 服务的首部字段 `Cookie`的工作机制是用户识别及状态管理。`Web` 网站为了管理用户的状态会通过 `Web` 浏览器,把一些数据临时写入用户的计算机内。接着当用户访问该`Web`网站时,可通过通信方式取回之前发放的`Cookie`; 调用 `Cookie` 时,由于可校验 `Cookie` 的有效期,以及发送方的域、路径、协议等信息,所以正规发布的 `Cookie` 内的数据不会因来自其他`Web` 站点和攻击者的攻击而泄露。 **为 Cookie 服务的首部字段:** ![image-20200317213803615](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/41.png) #### 6.1.Set-Cookie字段 当服务器准备开始管理客户端的状态时,会事先告知各种信息。 ``` Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31 GMT; path ``` **`Set-Cookie` 字段的属性 ** ![image-20200317213949707](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/42.png) * **expires 属性:** `Cookie` 的 `expires` 属性指定浏览器可发送 `Cookie` 的有效期。当省略 `expires` 属性时,其有效期仅限于维持浏览器会话`(Session)`时间段内。 这通常限于浏览器应用程序被关闭之前。 另外,一旦 `Cookie` 从服务器端发送至客户端,服务器端就不存在可以显式删除 `Cookie` 的方法。但可通过覆盖已过期的 `Cookie`,实现对客户端 `Cookie` 的实质性删除操作。 * **domain 属性:** 通过 `Cookie` 的` domain` 属性指定的域名可做到与结尾匹配一致。 比如,当指定 `example.com` 后,除 `example.com` 以外, `www.example.com`或 `www2.example.com `等都可以发送 `Cookie`。 因此, 除了针对具体指定的多个域名发送 `Cookie `之 外,不指定`domain` 属性显得更安全。 * **secure 属性:** `Cookie` 的` secure` 属性用于限制 `Web` 页面仅在 `HTTPS` 安全连接时,才可以发送 `Cookie`。 发送 `Cookie `时,指定` secure `属性的方法如下所示: ``` Set-Cookie: name=value; secure ``` 以上例子仅当在` https://www.example.com/(HTTPS) `安全连接的情况下才会进行` Cookie` 的回收。也就是说, 即使域名相同,`http://www.example.com/(HTTP) `也不会发生 `Cookie` 回收行为。 当省略 `secure` 属性时,不论 `HTTP `还是 `HTTPS`,都会对 `Cookie` 进行回收。 * **HttpOnly 属性:** `Cookie` 的 `HttpOnly `属性是 `Cookie` 的扩展功能,它使 `JavaScript `脚本无法获得 `Cookie`。 其主要目的为防止跨站脚本攻击`(Cross-sitescripting, XSS)` 对` Cookie` 的信息窃取。 发送指定 `HttpOnly` 属性的` Cookie` 的方法如下所示。 ``` Set-Cookie: name=value; HttpOnly ``` 通过上述设置,通常从` Web `页面内还可以对 `Cookie `进行读取操作。但使用 `JavaScript` 的 `document.cookie` 就无法读取附加` HttpOnly` 属性后的` Cookie `的内容了。 因此,也就无法在 `XSS` 中利用 JavaScript 劫`Cookie` 了。 #### 6.2.Cookie字段 首部字段 `Cookie` 会告知服务器,当客户端想获得 `HTTP `状态管理支持时, 就会在请求中包含从服务器接收到的 `Cookie`。 接收到多个`Cookie` 时,同样可以以多个 `Cookie `形式发送。 ``` Cookie: status=enable ``` ## 四、HTTP请求方法 **HTTP/1.1 的常用方法 :** ![image-20200318104329280](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/43.png) ### 1.GET `GET `方法用来请求访问已被` URI` 识别的资源。指定的资源经服务器端解析后返回响应内容。 举例: ![image-20200318104711164](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/44.png) ![image-20200318105633396](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/45.png) **GET方法也可以用来提交表单和其他数据:** ``` http://localhost/login.php?username=aa&password=1234 ``` 从上面的请求`URL`中,很容易就能辨认出表单提交的内容。`HTTP0.9`的时候只有`GET`方法,所以`GET`方法既能获取数据,也能提交数据,只不过提交的数据是拼接在`URL`后的不能提交太多且不安全;提交大量数据时使用`POST`方法。 ### 2.POST * `POST`方法功能与`GET`方法类似,是`GET`方法的延伸,主要用于向服务器提交数据量较大的**用户表单**数据; * 提交的数据放在请求报文的主体中,保证了提交数据的安全;这样就克服了`GET`方法提交的数据量太小和不能保密的缺点。 * `POST`方法的主要目的并不是获取响应主体的内容; ![image-20200318110800869](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/46.png) ### 3.PUT * `PUT`方法用来传输文件。 就像` FTP` 协议的文件上传一样, 要求在请求报文的主体中包含文件内容, 然后保存到请求` URI `指定的位置。 * `PUT`方法和`POST`很相似,最大的不同是:`PUT`是幂等的,`POST`是不幂等的。 即创建文件使用`POST`更新文件使用`PUT`; > 幂等:幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同; * 但是, 鉴于·`HTTP/1.1` 的 `PUT `方法自身不带验证机制, 任何人都可以上传文件 , 存在安全性问题, 因此一般的 `Web `网站**不使用该方法**。 ### 4.HEAD `HEAD` 方法和 `GET` 方法一样, 只是获取响应报文首部,不返回报文主体部分。 用于确认`URI` (超链接)的有效性及资源更新的日期时间等。 例如: ![image-20200318112642135](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/47.png) ### 5.DELETE * `DELETE` 方法用来删除文件,是与 `PUT` 相反的方法。`DELETE` 方法按请求 `URI` 删除指定的资源。 * 但是,`HTTP/1.1 `的 `DELETE` 方法本身和 `PUT `方法一样不带验证机制,所以一般的 `Web `网站也不使用 `DELETE` 方法。(怎么可能让人随便`rm -rf`) 举例: ![image-20200318113012177](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/48.png) ### 6.OPTIONS `OPTIONS `方法用来查询针对请求` URI` 指定的资源支持的方法。 ![image-20200318113110813](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/49.png) 示例: ![image-20200318113127546](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/49.5.png) ### 7.TRACE * 客户端通过 `TRACE` 方法可以查询发送出去的请求是怎样被加工修改/ 篡改的。 这是因为, 请求想要连接到源目标服务器可能会通过代理中转, `TRACE` 方法就是用来确认连接过程中发生的一系列操作。 * 但是,` TRACE` 方法本来就不怎么常用, 再加上它容易引发`XST`(`Cross-Site Tracing`, 跨站追踪) 攻击, 通常就更不会用到了。 * 发送请求时, 在 `Max-Forwards` 首部字段中填入数值, 每经过一个服务器端就将该数字减 `1`, 当数值刚好减到 `0 `时, 就停止继续传输, 最后接收到请求的服务器端则返回状态码` 200 OK `的响应。 ![image-20200318114809722](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/50.png) 示例: ``` //请求 TRACE / HTTP/1.1 Host: hackr.jp Max-Forwards: 2 响应: HTTP/1.1 200 OK Content-Type: message/http Content-Length: 1024 TRACE / HTTP/1.1 Host: hackr.jp Max-Forwards: 2(返回响应包含请求内容) ``` ### 8.CONNECT `CONNECT `方法要求在与代理服务器通信时建立隧道, 实现用隧道协议进行` TCP` 通信。 主要使用 `SSL`(`Secure Sockets Layer`, 安全套接层) 和` TLS`(`Transport Layer Security`, 传输层安全) 协议把通信内容加 密后经网络隧道传输。 ```http //格式 CONNECT 代理服务器名:端口号 HTTP版本 //例子 //请求 CONNECT proxy.hackr.jp:8080 HTTP/1.1 Host: proxy.hackr.jp //响应 HTTP/1.1 200 OK(之后进入网络隧道) ``` ## 五、HTTP状态管理 Cookie和Session,实现了HTTP的状态管理,Cookie是在客户端的,Session是在服务器的。 ### 1.Cookie `HTTP` 是**无状态协议**(高效率,不记仇),它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。 假设要求登录认证的` Web` 页面本身无法进行状态的管理(不记录已登录的状态) ,那么每次跳转新页面不是要再次登录,就是要在每次请求报文中附加参数来管理登录状态。 ![image-20200318090108406](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/51.png) 保留无状态协议这个特征的同时又要解决类似的矛盾问题,于是引入了` Cookie `技术。`Cookie `技术通过在请求和响应报文中写入` Cookie `信息来控制客户端的状态。 * `Cookie`实际上是一小段文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个`Cookie`; * 客户端浏览器会把`Cookie`保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该`Cookie`一同提交给服务器。服务器检查该`Cookie`,以此来辨认用户状态。 在一个网站地址栏输入: ``` javascript:alert(document.cookie) ``` 可以弹出该网站的`Cookie`信息: ![image-20200318125635655](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/52.png) `Cookie` 会根据从服务器端发送的响应报文内的一个叫做 `Set-Cookie` 的首部字段信息, 通知客户端保存`Cookie`。当下次客户端再往该服务器发送请求时, 客户端会自动在请求报文中加入 `Cookie` 值后发送出去。 服务器端发现客户端发送过来的` Cookie `后, 会去检查究竟是从哪一个客户端发来的连接请求, 然后对比服务器上的记录, 最后得到之前的状态信息。 #### 第一次:没有 Cookie 信息状态下的请求 ![image-20200318090429111](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/53.png) * **请求报文(没有 Cookie 信息的状态)** ![image-20200318090524295](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/54.png) * **响应报文(服务器端生成 Cookie 信息) ** ![image-20200318090543542](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/55.png) #### 第二次:存有 Cookie 信息状态的请求 ![image-20200318090456328](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/56.png) * **请求报文(自动发送保存着的 Cookie 信息) ** ![image-20200318090609670](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/57.png) ### 2.Session * `Session`是另一种记录客户状态的机制,保存在**服务器**上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上; * 客户端浏览器再次访问时只需要从该`Session`中查找该客户的状态就可以了; ![image-20200318140020730](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/58.png) `Cookie`和`Session`非常相似,`Cookie`相当于客户端持有的**通行证**,Session相当于服务器上的**通行名册**。 **保存Session ID的方式** * `Cookie` * `URL`重写 * 隐藏表单 **Session的有效期** * `Session`超时失效:被动失效,如果超过规定时间没有再次访问服务器,`Session`将失效; * 程序调用`HttpSession.invalidate()`:主动失效; * 服务器进程被停止; ### 3.**Token** **Token的引入** `Token`是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,`Token`便应运而生。 **Token的定义** `Token`是服务端生成的一串字符串,以作客户端进行请求的一个**令牌**,当第一次登录后,服务器生成一个`Token`便将此`Token`返回给客户端,以后客户端只需带上这个`Token`前来请求数据即可,**无需再次带上用户名和密码**。最简单的`token`组成`:uid`(用户唯一的身份标识)、`time`(当前时间的时间戳)、`sign`(签名,由`token`的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接`token`请求服务器)。 **使用Token的目的** `Token`的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。 **Session管理及Cookie应用** ![image-20200318154807240](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/59.png) * **步骤 1**:客户端把用户 `ID` 和密码等登录信息放入报文的实体部分,通常是以 `POST `方法把请求发送给服务器。而这时,会使用 `HTTPS`通信来进行` HTML`表单画面的显示和用户输入数据的发送。 * **步骤 2**:服务器会发放用以识别用户的 `Session ID`。通过验证从客户端发送过来的登录信息进行身份认证, 然后把用户的认证状态与`Session ID `绑定后记录在服务器端。 向客户端返回响应时,会在首部字段`Set-Cookie `内写入 `SessionID`(如 `PHPSESSID=028a8c…`) 。 为防止`Session ID` 被第三方盗走,服务器端需要对其进行有效性管理;并且为减轻跨站脚本攻击`(XSS)` 造成的损失,建议事先在 `Cookie`内加上 `httponly` 属性。 * **步骤 3**: 客户端接收到从服务器端发来的 `Session ID `后,会将其作为`Cookie` 保存在本地。下次向服务器发送请求时,浏览器会自动发送`Cookie`,所以 `Session ID` 也随之发送到服务器。服务器端可通过验证接收到的 `Session ID` 识别用户和其认证状态。 ### 4.Cookie与Session的区别 * **存放位置不同**:`Cookie`存放在客户端,`Session`保存在服务器端; * **安全性(隐私策略)不同**:`Cookie`存储在浏览器中,对客户端是可见的,客户端的一些程序可能会窥探或修改`Cookie`的内容;而`Session`存储在服务器端,对客户端来说是透明的;如果想要使用`Cookie`需要对其进行加密; * **有效期上的不同**:设置`Cookie`很大的过期时间,`Cookie`就能被浏览器保存很长时间;而服务器会定期清理超时的`Session ID`避免出现过大压力;但是`Session`依赖于类似`Session ID`这样的`Cookie`,而`Cookie`对`Session ID`过期时间默许为`-1`。所以只要关闭了浏览器,即一次会话结束后,该`Session`就失效了; * **对服务器造成的压力不同**:`Session`是保存在服务器端的,每个用户都产生一个`Session`,假如并发访问的用户十分多,会产生十分多的`Sssion`,耗费大量的内存;而`Cookie`保存在客户端,不太占用服务器的资源; ## 六、HTTP协议的身份认证 * `BASIC`认证(基本认证) * `DIGEST`(摘要认证) * `SSL`客户端认证 * `FormBase`认证(基于表单认证) ### 1.BASIC认证 **BASIC 认证的认证步骤** : * **步骤 1**:当请求的资源需要` BASIC `认证时,服务器会随状态码 `401 Authorization Required`,返回带 `WWW-Authenticate` 首部字段的响应。该字段内包含认证的方式`(BASIC)`及` Request-URI `安全域字符`(realm)`。 * **步骤 2**: 接收到状态码` 401` 的客户端为了通过 `BASIC` 认证, 需要将用户` ID` 及密码发送给服务器。 发送的字符串内容是由用户 `ID` 和密码构成, 两者中间以冒号`(:) `连接后,再经过` Base64` 编码处理。 假设用户` ID` 为 `guest`,密码是` guest`,连接起来就会形成 `guest:guest` 这样的字符串。 然后经过 `Base64` 编码,最后的结果即是`Z3Vlc3Q6Z3Vlc3Q=`。 把这串字符串写入首部字段 `Authorization` 后, 发送请求。 * **步骤 3**: 接收到包含首部字段` Authorization `请求的服务器,会对认证信息的正确性进行验证。 如验证通过, 则返回一条包含 `Request-URI`资源的响应。 ![image-20200318145152607](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/60.png) `BASIC` 认证虽然采用` Base64 `编码方式,但这不是加密处理。不需要任何附加信息即可对其解码。换言之,由于明文解码后就是用户 `ID`和密码,在` HTTP` 等非加密通信的线路上进行 `BASIC` 认证的过程中,如果被人窃听,被盗的可能性极高。 因此并不常用。 ### 2.DIGEST 认证 为弥补·`BASIC`认证存在的弱点, 从 `HTTP/1.1` 起就有了 `DIGEST` 认证。` DIGEST` 认证同样使用质询 / 响应的方式 `(challenge/response)`,但不会像 `BASIC` 认证那样直接发送明文密码。 所谓质询响应方式是指, 一开始一方会先发送认证要求给另一方, 接着使用从另一方那接收到的**质询码**计算生成**响应码**。 最后将响应码返回给对方进行认证的方式。 ![image-20200318150407496](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/61.png) 因为发送给对方的只是响应摘要及由质询码产生的计算结果,所以比起 `BASIC` 认证,密码泄露的可能性就降低了。 **DIGEST 认证的认证步骤: ** * **步骤 1**:请求需认证的资源时,服务器会随着状态码 `401:Authorization Required`,返 回带 `WWW-Authenticate `首部字段的响应。该字段内包含质问响应方式认证所需的临时质询码(随机数,`nonce`) 。 首部字段` WWW-Authenticate` 内必须包含 `realm` 和 `nonce` 这两个字段的信息。客户端就是依靠向服务器回送这两个值进行认证的。 `nonce `是一种每次随返回的 `401` 响应生成的任意随机字符串。该字符串通常推荐由 `Base64 `编码的十六进制数的组成形式,但实际内容依赖服务器的具体实现。 * **步骤 2**: 接收到 `401 `状态码的客户端,返回的响应中包含 `DIGEST `认证必须的首部字段` Authorization` 信息。 首部字段` Authorization` 内必须包含` username`、 `realm`、` nonce`、 `uri` 和r`esponse `的字段信息。其中,`realm `和 `nonce `就是之前从服务器接收到的响应中的字段。 * **步骤 3**: 接收到包含首部字段 `Authorization` 请求的服务器,会确认认证信息的正确性。 认证通过后则返回包含 `Request-URI `资源的响应。并且这时会在首部字段` Authentication-Info `写入一些认证成功的相关信息。 ![image-20200318151408496](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/62.png) `DIGEST `认证提供了高于` BASIC `认证的安全等级,但是和 `HTTPS `的客户端认证相比仍旧很弱。 `DIGEST `认证提供防止密码被窃听的保护机制,但并不存在防止用户伪装的保护机制 。因此使用范围不大。 ### 3.SSL 客户端认证 从使用用户` ID `和密码的认证方式方面来讲,只要二者的内容正确即可认证是本人的行为。但如果用户 `ID `和密码被盗,就很有可能第三者冒充。利用` SSL`客户端认证则可以避免该情况的发生。 `SSL`客户端认证是借由 `HTTPS` 的客户端证书完成认证的方式。凭借客户端证书认证,服务器可确认访问是否来自已登录的客户端。 **SSL 客户端认证的认证步骤 :** 为达到` SSL`客户端认证的目的 需要事先将客户端证书分发给客户端,且客户端必须安装此证书。 * **步骤 1**:接收到需要认证资源的请求,服务器会发送 `Certificate Request` 报文,要求客户端提供客户端证书。 * **步骤 2**:用户选择将发送的客户端证书后,客户端会把客户端证书信息以 `Client Certificate `报文方式发送给服务器。 * **步骤 3**: 服务器验证客户端证书验证通过后方可领取证书内客户端的`165`公开密钥, 然后开始` HTTPS `加密通信。 **SSL 客户端认证采用双因素认证 :** * 在多数情况下,`SSL`客户端认证不会仅依靠证书完成认证,一般会和**基于表单认证**组合形成一种双因素认证`(Two-factorauthentication) `来使用。 * 换言之,第一个认证因素的` SSL`客户端证书用来认证客户端计算机,另一个认证因素的密码则用来确定这是用户本人的行为。 * 使用 `SSL`客户端认证需要用到客户端证书。而客户端证书需要支付一定费用才能使用。 ### 4.基于表单认证 * 基于表单的认证方法并不是在`HTTP`协议中定义的; * 使用由`Web`应用程序各自实现基于表单的认证方式; * 通过`Cookie`和`Session`的方式来保持用户的状态(具体见上); 也就是常见的登录: ![image-20200318154207699](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/64.png) 输入已事先登录的用户` ID`(通常是任意字符串或邮件地址) 和密码等登录信息后,发送给` Web `应用程序,基于认证结果来决定认证是否成功。 ## 七、HTTP的长连接与短连接 `HTTP`协议是基于请求/响应模式的,因此只要服务端给了响应,本次`HTTP`请求就结束了;`HTTP`的长连接和短连接本质上是`TCP`的**长连接**和**短连接**; ### 1.短连接 完成一次通信之后,客户端主动断开TCP连接; `HTTP/1.0`中,默认使用的是**短连接**。也就是说,浏览器和服务器每进行一次`HTTP`操作,就建立一次连接(三次握手),结束就中断(四次挥手); ### 2.长连接 完成一次通信之后,客户端不主动断开 `TCP`连接,而是复用该`TCP`连接; `HTTP/1.1`起,默认使用**长连接**,用以保持连接特性。此时通用首部字段中的`Connection`字段值为:`Keep-Alive`; 长连接适用于频繁地传输数据的客户端和服务器,为了防止过多的TCP连接影响服务器性能,需要对长时间不用的连接进行释放; ## 八、代理、网关与隧道 `HTTP `通信时,除客户端和服务器以外,还有一些用于通信数据转发的应用程序,例如代理、网关和隧道。它们可以配合服务器工作。 这些应用程序和服务器可以将请求转发给通信线路上的下一站服务器,并且能接收从那台服务器发送的响应再转发给客户端。 ### 1.代理 **代理服务器:** 代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端“**中间人**”的角色,接收由客户端发送的请求并转发给服务器,同时也接收服务器返回的响应并转发给客户端。 ![image-20200318162610556](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/65.png) 代理服务器的基本行为就是接收客户端发送的请求后转发给其他服务器。代理不改变请求` URI`,会直接发送给前方持有资源的目标服务器。 持有资源实体的服务器被称为源服务器,从源服务器返回的响应经过代理服务器后再传给客户端。 ![image-20200318162711944](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/66.png) > 每次通过代理服务器转发请求或响应时,会追加写入 `Via` 首部信息。 **使用代理服务器的理由:** 利用缓存技术(稍后讲解)减少网络带宽的流量,组织内部针对特定网站的访问控制(墙),以获取访问日志为主要目的,等等。 ![image-20200318163146824](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/67.png) **代理使用方法:** 代理有多种使用方法,按两种基准分类。一种是是否使用缓存,另一种是是否会修改报文。 * **缓存代理 ** 代理转发响应时,缓存代理(`Caching Proxy`)会预先将资源的副本(缓存)保存在代理服务器上。当代理再次接收到对相同资源的请求时,就可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回。 * **透明代理 ** 转发请求或响应时,不对报文做任何加工的代理类型被称为**透明代理**(`Transparent Proxy`)。反之,对报文内容进行加工的代理被称为**非透明代理**。 ### 2.网关 网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。有时客户端可能都不会察觉,自己的通信目标是一个**网关**。 ![image-20200318163648918](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/68.png) 网关的工作机制和代理十分相似。但是`Web`网关在一侧使用`HTTP`协议,在另一侧使用另一种协议(比如`FTP`、`SMTP`)。 * (`HTTP/`)服务器端网关:通过`HTTP`协议与客户端对话,通过其他协议与服务器通信; * (`/HTTP`)客户端网关:通过其他协议与客户端对话,通过`HTTP`协议与服务器通信; **常见的网关类型:** * (`HTTP/`*)服务器端`Web`网关; * (`HTTP/HTTPS`)服务器端安全网关:即客户端用`HTTP`与网关通信,网关用`HTTPS`与服务器通信; * (`HTTPs/HTTP`)客户端安全加速器网关:即客户端用`HTTPs`与网关通信,网关用`HTTP`与服务器通信; 也就是**安全网关**,将通过网关的不安全的`HTTP`转换为安全的`HTTPS`; * 资源网关:客户端通过HTTP连接到应用程序的服务器,服务器并不回送文件,而是将请求通过网关API发送给运行在服务器上的应用程序,应用程序将请求资源会送给客户端。这样的客户端可能是一些网络摄像头,电子识别系统等; 利用网关能提高通信的**安全性**,因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。比如,网关可以连接数据库,使用`SQL`语句查询数据。另外,在` Web` 购物网站上进行信用卡结算时,网关可以和信用卡结算系统联动。 ### 3.隧道 隧道可按要求建立起一条与其他服务器的通信线路,届时使用` SSL`等加密手段进行通信。隧道的目的是确保客户端能与服务器进行安全的通信。 隧道本身不会去解析` HTTP` 请求。也就是说,请求保持原样中转给之后的服务器。隧道会在通信双方断开连接时结束。 ![image-20200318165852154](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/69.png) > 通过隧道的传输,可以和远距离的服务器安全通信。隧道本身是透明的,客户端不用在意隧道的存在。 ## 九、HTTP缓存 缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。 缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。 ![image-20200318170530364](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/70.png) ![image-20200318170549956](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/71.png) 缓存服务器的优势在于利用缓存可避免多次从源服务器转发资源。因此客户端可就近从缓存服务器上获取资源, 而源服务器也不必多次处理相同的请求了。 ### 1.缓存的有效期限 即便缓存服务器内有缓存,也不能保证每次都会返回对同资源的请求。因为这关系到被缓存资源的有效性问题。 当遇上源服务器上的资源更新时,如果还是使用不变的缓存,那就会演变成返回更新前的“旧”资源了。 即使存在缓存,也会因为客户端的要求、缓存的有效期等因素,向源服务器确认资源的有效性。若判断缓存失效, 缓存服务器将会再次从源服务器上获取“新”资源。 ![image-20200318170746847](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/72.png) ### 2.客户端的缓存 缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。以`Internet Explorer` 程序为例,把客户端缓存称为临时网络文件(`Temporary Internet File`); 浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取; ![image-20200318170932065](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/73.png) 另外,和缓存服务器相同的一点是, 当判定缓存过期后, 会向源服务器确认资源的有效性。若判断浏览器缓存失效,浏览器会再次请求新资源。 ## 十、HTTP缓存的工作方式(强制缓存与协商缓存) ### 1.场景一 让服务器与浏览器约定一个文件过期时间——`Expires` ![image-20200318180301511](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/74.png) 在`Expires`没有过期的情况下,客户端(浏览器)发出请求时,直接使用`HTTP`本地缓存并返回状态码`200`,这种`HTTP`工作方式称为**强制缓存**; ### 2.场景二 让服务器与浏览器在约定文件过期时间`Expires`的基础上,再加一个文件最新修改时间的对比——`Last-Modified`与`if-Modified-Since` ![image-20200318180227578](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/75.png) * **情况1**:如果`Expires`没有过期,浏览器直接使用`HTTP`本地缓存,即采用**强制缓存**; * **情况2**:如果`Expires`过期了,那么浏览器在请求服务器的时候,就带上了文件最新修改时间,这个字段是在请求头里面加上了`If-Modified-Since`字段,其实该字段的值就是上次请求时服务器返回的`Last-Modified`字段的值;服务器会把请求头里文件的最新修改时间`If-Modified-Since`的值与服务器上的文件最新修改时间`Last-Modified`的值进行比较: * 如果`If-Modified-Since` **不等于**`Last-Modified`,说明浏览器缓存的资源(`f.js`)发生改变,服务器就会去查找最新的`f.js`,同时再次返回`Expires`、`f.js`、`Last-Modified`,返回的状态码为`200`; * 如果`If-Modified-Since` **等于**`Last-Modified`,说明浏览器缓存的资源(`f.js`)没有发生改变,浏览器可以继续使用`HTTP`本地缓存,此时服务器返回状态码`304`;这种方式称为**协商缓存** ### 3.场景三 让服务器在过期时间`Expires`+`Last-Modified`的基础上,增加一个文件唯一标识`Etag`与`If-None-Match`配成一对使用;除此之外,`Expires`不稳定,再加入一个`Max-age`来加以替代(`Max-age`优先级更高); ![image-20200318185030563](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/76.png) * 在60s内,浏览器不再向服务器发起请求,直接使用本地缓存这与`Expires`相似。 * 60s后:浏览器带上`If-Modified-Since`和`If-None-Match`(也就是上次服务器返回的`Etag`值)发起请求,服务器会对比`If-None-Match`与服务器端的`Etag`值,这时即使浏览器也提供了`If-Modified-Since`也不会再与`Last-Modified`进行对比,因为`Etag`的优先级比`Last-Modified`高(更精准); * 如果`If-None-Match`**不等于**`Etag`,说明`f.js`文件已被修改,服务器就会返回最新的`f.js`和全新的`Etag`与`Max-age`(比如`60`),当然也会顺便把`Expires`与`Last-Modified`返回(尽管没用);返回的状态码为`200`; * 如果`If-None-Match`**等于**`Etag`,说明`f.js`文件没有被修改,这时服务器返回的状态码为`304`,告诉浏览器继续使用原来的本地缓存。这种方式属于**协商缓存**; **有了`Last-Modified`为什么还要用`Etag`呢?** 你可能会觉得使用`Last-Modified`已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要`Etag`呢?`HTTP1.1`中`Etag`的出现主要是为了解决几个`Last-Modified`比较难解决的问题: * 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新`GET`; * 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说`1s`内修改了`N`次),`If-Modified-Since`能检查到的粒度是`s`级的,这种修改无法判断(比如淘宝每`ms`都会更新数据); * 某些服务器不能精确的得到文件的最后修改时间; 这时,利用`Etag`能够更加准确的控制缓存,因为`Etag`是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符。 `Last-Modified`与`ETag`是可以一起使用的,服务器会优先验证`ETag`,一致的情况下,才会继续比对`Last-Modified`,最后才决定是否返回`304`。 ### 4.强制缓存与协商缓存 **强制缓存:**直接使用`HTTP`本地缓存,此时服务器返回状态码`200`; **协商缓存:**向服务器确认`HTTP`本地缓存的资源是否发生变化,没变化后再使用`HTTP`本地缓存,此时服务器返回状态码`304`;资源发生变化直接返回最新资源,状态码为`200`;可以这样理解凡是返回`304`状态码,都属于**协商缓存**; **强缓存和协商缓存的区别:** | 缓存 | 获取资源形式 | 状态码 | 发送请求到服务器 | | :------: | :----------: | :-----------------: | :----------------------------------: | | 强缓存 | 从缓存读取 | 200(From Cache) | 否,直接从缓存读取 | | 协商缓存 | 从缓存读取 | 304(Not Modified) | 是,通过服务器告知浏览器缓存是否可用 | 请求头`Cache-Control`的值为**no - store**时表示不允许浏览器(客户端)使用缓存,会直接跳到**协商缓存**; ### 5.缓存改进方案 上述的缓存方案存在一个问题:当`Expires`或`Max-age`没有过期时,浏览器无法**主动**确认本地缓存是否发生变化; #### 5.1.md5/hash缓存 通过不缓存`html`,为静态文件添加`MD5`或者`hash`标识,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题;具体过程为:第一次加载静态文件时,某位置指定加载`f-hash1.js`,第二次加载静态文件时同一个位置指定加载`f-hash2.js`,此时浏览器就会重新向服务器请求数据了; #### 5.2.CDN缓存(最常用) `CDN`是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率; 比如可以把`CDN`理解为各个城市的快递分发站点,源服务器看作快递总仓库; **CDN缓存工作方式**: * **第一次缓存:** ![image-20200318194542397](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/77.png) * **后续请求:** ![image-20200318194515210](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/78.png) `CDN`节点会代替服务器处理浏览器的请求,会有几种情况: * 情况一:`CDN`节点缓存的文件还没过期,于是返回`304`给浏览器,浏览器此次请求被拦截(**协商缓存**); * 情况二:`CDN`节点发现自己缓存的文件过期了,为了保险起见自己发送请求给服务器成功拿回了最新的数据,然后再交还给浏览器; 可以发现,`CDN`缓存问题与`HTTP`缓存是一样的。只不过`CDN`缓存不过期浏览器始终被拦截,无法拿到最新的文件;另外的不同点在于`CDN`相当于一个平台可以手动登录更新缓存,这也就变相解决了不能控制`HTTP`本地缓存的问题。 ### 6.浏览器操作对HTTP缓存的影响 | 用户操作 | Expires/Cache-Control | Last-Modified/Etag | | :-----------: | :-------------------: | :----------------: | | 地址栏回车 | 有效 | 有效 | | 页面链接跳转 | 有效 | 有效 | | 新开窗口 | 有效 | 有效 | | 前进、后退 | 有效 | 有效 | | F5刷新 | **无效** | 有效 | | Ctrl + F5刷新 | **无效** | **无效** | 由上表可知:对于`Last-Modified`和`Etag`字段来说,只有在进行`Ctrl + F5`强制刷新时,这两个字段对缓存是否有效的控制才会失效。即强制刷新后,浏览器不会使用本地缓存,而是直接向服务器发起请求。 ## 十一、内容协商机制 指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为**合适**的资源。内容协商会以响应资源的语言,字符集,编码方式等作为判断的基准。 有三种方式: * **客户端驱动** 由客户端发起请求,服务器发送可选项列表,客户端作出选择后在发送第二次请求; * **服务器驱动** 服务器检查客户端的请求头部集并决定提供哪个版本的页面; * **透明协商** 某个中间设备(通常是缓存代理)代表客户端进行协商; ### 1.服务器驱动 服务器驱动内容协商:**请求首部集**; * **Accept**:告知服务器发送何种媒体类型; * **Accept-Language**:告知服务器发送何种语言; * **Accept-Charset**:告知服务器发送何种字符集; * **Accept-Encoding**:告知服务器采用何种编码; 服务器驱动内容协商:**实体首部集**; * **Content-Type** * **Content-Language** * **Content-Type** * **Content-Encoding** 与请求首部集一一对应; ## 十二、断点续传和多线程下载 `HTTP`是通过在`Header`里两个参数实现的,客户端发出请求时对应的是`Range`,服务器端响应时对应的是`Content-Range`,如果续存成功返回`206`,如果文件有变动返回`200`和新文件的内容; #### 1.Range 用于请求头中,指定第一个字节的位置和最后一个字节的位置,格式为: ``` //格式(左开右闭) Range:(unit = first byte pos) - [last byte pos] //示例 Range: bytes=5001-10000 ``` 接收到附带 `Range` 首部字段请求的服务器,会在处理请求之后返回状态码为 `206 Partial Content` 的响应。 无法处理该范围请求时,则会返回状态码 `200 OK` 的响应及全部资源。 **断点续传过程** * `1`.客户端下载一个`1024K`的文件,已经下载了其中的`512K`。 * `2`.网络中断,客户端请求续传,因此需要在`HTTP`头中申明本次需要续传的片段: `Range:bytes`=`512000~`这个头通知服务器端从文件的`512K`位置开始传输文件; * `3`.服务器收到断点续传请求,从文件的`512K`开始传输,并且在`HTTP`头中增加: ``` Content-Range:bytes 512000-/1024000 ``` 并且此时服务端返回的`HTTP`状态码应该是`206 Partial Content`,而不是`200`; ## 十三、HTTPS `HTTPS`使用的是`TSL`协议(`SSL`是`TSL`协议的一种); #### 1.HTTPS的功能 * **内容加密** * 非对称密钥加密:传输公钥时可能被截获并掉包,解决方案:使用第三方机构颁发的证书加密公钥(根据服务器地址等多个信息生成,无法被第三方伪造),浏览器收到后使用证书机构颁发的公钥进行解密(前提是浏览器要信任同一个证书颁发机构)解密结果与用证书生成的规则再生成一个签名对比一致就是真证书; * 对称密钥加密:中间人随意截获 * **身份认证** * 数字证书 * **数据完整性** #### 2.HTTPS的使用成本 `HTTPS`是一个大趋势 * **证书费用以及更新维护** * 证书现在不贵,也有免费的; * **HTTPS降低用户访问速度** * 经过合理的优化(比如`SPDY`)和部署甚至可以比`HTTP1.0`快,不过这也是成本之一就是了; * **消耗CPU资源,需要增加大量机器** * 需要多次计算 #### 3.HTTPS对性能的影响 * **协议交互所增加的网络RTP(往返时延)** * **加解密相关计算的耗时** **网络耗时:** `HTTP`只需要通过`TCP`的三次握手就能建立`HTTP`连接: ![image-20200319092450746](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/79.png) 而`HTTPS`除了`TCP`的三次握手外,甚至还需要耗费额外的`7`个`RTP`进行验证 ![image-20200319092433164](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/80.png) 关于`302`自动跳转,这是因为,比如访问百度,我们输入网址全称而是输入`baidu.com`,所以会自动跳转至`HTTPS`,这本身也需要耗时; 并且跳转后,`URI`不一样了,浏览器要与服务器重新通过三次握手建立`TCP`连接; 之后还要进行`TLS`协商,比如密钥交换算法,对称加密算法,内容一致性校验算法,证书签名算法等等;浏览器获取到证书后,也需要校验证书的有效性,比如证书是否过期,是否撤销等等; 接着,浏览器首先获取证书里的`CA`域名如果该`CA`域名没有命中缓存,浏览器需要解析域名的`DNS`,这个`DNS`解析至少耗费一个`RTP`; `DNS`解析到`IP`之后就要完成三次握手,建立`CA`站点的`TCP`连接,这又耗费一个`RTP`; 再接着浏览器发送`OCSP`请求,获取响应耗费一个`RTP`; > 关于`OCSP`:在线证书状态协议,它是维护服务器和其他网络资源安全性的两种普遍模式之一,另外一个叫做`CRL`证书注销列表;当用户试图访问一个服务器的时候,在线证书状态协议发送一个对于证书状态信息的请求,服务器会回复一个有效、过期、未知的响应;协议规定了服务器和客户端应用程序通信的语法;在线证书协议给了用户到期证书一个宽限期,这样用户就可以在更新证书前的一段时间继续访问服务器,所以这里就需要发起一个对于证书状态的请求,也需要消耗一个`RTP` 最后就是`TLS`完全握手阶段`2`,这个阶段主要进行密钥协商,耗时一个`RTP`;随后进行应用层的`TCP`数据通信。 **计算耗时** * 浏览器计算耗时; * 服务器计算耗时; #### 4.HTTPS常见问题 * `HTTPS`需要安装证书 * 大型网站比如百度,从`HTTP`升级为`HTTPS`比较困难(不能因为升级而降低用户体验这样就本末倒置了) * `HTTPS`并不能解决所有安全问题(比如`XSS`攻击,木马等),只是能更加安全的传输数据 #### 5.影响HTTP网络请求的因素 * **带宽** * **延迟** * 一条连接上只可发送**一个**请求; * 请求只能从**客户端开始**,客户端不可以接收除响应以外的指令; * 请求/响应头部**不经压缩**就发送,每次互相发送**相同**的头部造成的浪费很多; * 非强制压缩发送; ## 十四、WebSocket 可以理解为`WebSocket`是为了让`HTTP`支持长连接而打的一个大补丁; ![image-20200319105842250](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/81.png) `WebSocket`是一个持久化的`HTTP`,而`HTTP`本身是非持久化的如下图所示:(虽然有`Keep-Alive`) ![image-20200319105852095](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/82.png) #### 1.WebSocket的握手 **请求:** ![image-20200319110017779](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/83.png) **响应:** ![image-20200319110157916](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/84.png) `Upgrade`:表示升级为`WebSocket` #### 2.WebSocket的作用 **HTTP的瓶颈** **请求**只能从客户端发起,客户端不可以接收除了**响应**之外的指令;当客户端需要监听服务器上的内容时,在HTTP中有一些优化处理方式,常用的用:**Ajax轮询**,**Long Poll** * **Ajax轮询** 原理为,客户端每隔几秒就发送一次请求,询问服务器到底有没有新消息;若有服务器返回新消息,没有就返回提示信息,如此循环: ![image-20200319111653521](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/85.png) * **Long Poll长轮询** 与**Ajax轮询**原理相似,客户端先发出请求,直到服务器上有新数据返回之前,都不再发送请求,如此循环: ![image-20200319111724771](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/86.png) **缺陷:**两种方式都非常消耗资源,**Ajax轮询**需要服务器有很快地处理**速度**;**Long Poll**需要服务器有很大**容量**; * **异常情况** ![image-20200319111742047](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/87.png) **WebSocket解决上上述问题** 首先使用`HTTP`协议通知服务器升级到`WebSocket`协议,随后在`WebSocket`协议中,服务器端是可以主动推送数据给客户端的,详细过程: ![image-20200319111934039](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/88.png) **WebSocket的特点** 相比于`HTTP`的长连接,`WebSocket`具有以下特点 * 真正的**全双工方式**:服务器可以主动推送,`HTTP`的长连接仍然是客户端主动发起请求的; * 减少**通信量**:不需要重复传输`HTTP Header`等信息; * 持久性连接:只要进行一次`HTTP`连接,两者就能创建持久的`WebSocket`连接; ## 十五、SPDY **SPDY**是`HTTP`的增强,在向下兼容的情况下,在`TLS`层上新增一层会话层`SPDY`,使用这个会话层来实现`SPDY`协议,也就是说现有的服务格式均不用改变吗;**SPDY**是对`HTTP`的一个更好的实现和支持; ![image-20200319120419163](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/89.png) #### 1.HTTP的缺陷 * **单路连接,请求低效:**最大的弊端所在:每个`TCP`连接只能对应一个`HTTP`请求;也就是每个`HTTP`请求只能请求一个资源;浏览器只能通过建立多个连接来解决低效问题。 * **对请求严格的先进先出:**如果中间的某个请求处理时间比较长的话,就会阻塞后面的请求; * **只允许由客户端主动发起请求:**客户端只能接收服务器发出的响应,服务器无法主动推送信息; * **HTTP的头部冗余:**`HTTP`的头在一个会话里是反复传送的,中间的冗余信息比如:`User-Agent`、`Host`的等不需要重复发送的信息也在不断地重复发送,浪费带宽和资源; #### 2.SPDY的改进 所以基于`HTTP`的上述缺陷,**SPDY**进行了以下改进: * **多路复用请求优化**:`SPDY`规定在一个`SPDY`连接内可以有无限个并行的请求,即多个并发的请求共用一个`TCP`会话;只需要建立一个`TCP`连接就可以传送网页上的所有资源;减少了时延,节省了资源,把`TCP`连接的效率发挥到了最高; * **可以设置请求的优先级**:不必遵守`HTTP`那样的先进先出,而是可以优先传输`CSS`这些更重要的资源,然后再传输网站图标这样不太重要的资源。 * **支持服务器推送功能**:可以实现预加载,比如浏览器请求了`style.css`,服务器就会主动把`style.js`推送给浏览器。这样浏览器请求`style.js`是就可以直接使用本地缓存了;这 与`WebSocket`不同在于,这是**资源**的主动推送; * **SPDY压缩了HTTP头**:舍弃了不必要的`Header`头,可以节省多余数据造成的等待时间,占据的带宽等; * **强制使用SSL传输协议**:客户端全部的请求都要经过`SSL`加密后才能传输; **直观的影响** 对于前端工程师而言,页面优化永远是一个课题。有了`SPDY`的请求优化,可以将请求顺序重新编排,这样很大程度上缓解了页面加载时图片请求带来的影响;减少了`HTTP`的请求; ## 十六、HTTP2.0 上面所讲的`SPDY`后来被谷歌放弃了,转而成为了`HTTP2.0`的前身,基于`SPDY`的核心改造升级开发出了`HTTP2.0`。所以两者有比较多相似的地方: ![image-20200319120435914](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/90.png) #### 1.HTTP2.0性能增强的核心:二进制分帧 在`HTTPS`的基础上新增了二进制分帧层:`Binary Framing`,在该层上`HTTP2.0`会将所有的传输信息分割成更小的消息和帧,并对其采用二进制格式的编码; 如下图所示: ![image-20200319120435914](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/90.5.png) * 请求头信息被封装进了`HEADERS frame`中,请求报文主体被封装进了`DATA frame`中; * `HTTP2.0`的通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息由一个或多个帧组成。这些帧可以乱序发送,然后再根据每个帧首部的流标识符重新组装。 #### 2.HTTP2.0首部压缩 `HTTP2.0`在服务器端和客户端使用**首部表**来跟踪和存储之前发送的键值对,对于相同的数据不再通过每次请求和响应发送,通讯期间几乎不会改变通用的键值对,比如:`Host`、`User-agent`等只需要发送一次;如果这个请求不包含首部,那么首部的开销就变为`0`字节了,此时首部都自动使用之前发送请求的首部; 如下图所示,`Request # 2`中只需要在`HEADERS frame`里发送`:path`这个变化的头部即可,其他头部信息直接沿用`Request #1`的请求头;或者说新增或变化的头部信息会被追加到新的首部表中,如图中的`Request #2`。它在`HTTP2.0`的连接存续期内是始终存在的,由客户端和服务器端共同地渐进地更新; ![image-20200319121457874](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/91.png) #### 3.HTTP2.0多路复用 多路复用这也是继承于`SPDY`协议的,`HTTP2.0`所有的通信都在一个`TCP`连接上完成。`HTTP2.0`把`HTTP`通信的基本单位缩小为一个一个的帧,这些帧对应于逻辑流里面的信息,并行的在同一个`TCP`连接上双向交换; ![image-20200319122435057](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/92.png) `TCP`连接性能的关键在于低延迟。大多数`HTTP`连接的时间都很短,而且是突发性的,而`TCP`只在长时间传输连接,传输大块数据的时候效率是最高的;`HTTP2.0`通过让所有的数据流公用一个`TCP`连接可以更有效地使用`TCP`连接,让高带宽也能真正地服务于`HTTP`的性能提升上。 **但链接多资源的优势** * 可以减少**服务器建立大量链接的压力**,内存占用更少,连接吞吐量变大了。 * 由于`TCP`连接减少而使**网络拥塞状况**得以改观; * 慢启动时间减少,**拥塞**和**丢包**恢复速度更快; 也就是说,资源合并减少请求的方式,对于`HTTP2.0`来说是没有效果,只会开发者无用的工作量而已。所以当`HTTP2.0`普及之后,像雪碧图呀,文件合并等就没有多大意义了。 #### 4.并行双向字节流的请求和响应 ![image-20200319130500653](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/93.png) 简单点说就是可以**乱序发送**,在`HTTP2.0`上客户端和服务器可以把`HTTP`数据的消息分解为互不依赖的数据帧,然后乱序发送,最后在接收端把这些乱序帧重新组合起来。如图所示,同一个连接有多个不同方向的数据流在传输,所以客户端可以一边乱序地发送数据帧,也可以接收服务器的响应;服务器端也是如此都是双向的。 所以:把`HTTP`消息分解为独立的帧交错发送,然后在另一端重新组装是`HTTP2.0`一项很重要的增强; 这一特性会发生连锁反应带来巨大的性能提升: * 并行交错地发送**请求**,请求之间**互不影响**; * 并行交错地发送**响应**,响应之间**互不干扰**; * 只是用一个连接即可**并行发送**多个请求和响应; * 消除不必要的延迟,减少页面加载的时间; #### 5.请求优先级 `HTTP2.0`的这一特性也是继承于`SPDY`,服务器处理不同的流采取不同的优先策略; * 高优先级的流都应该优先发送; * 优先级不是绝对的; * 不同优先级混合也是必须的; #### 6.服务器推送 毕竟`HTTP2.0`的核心是从`SPDY`的基础上衍生而来的;服务器可以对客户端的一个请求发送多个响应,即除了对最初请求的响应之外服务器还可以额外向服务器推送其他资源,而无需客户端明确请求;如图所示:客户端请求了`html`文件,服务器就会把`js`与`css`文件推送给客户端: ![image-20200319132715028](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/94.png) ## 十七、WebDAV协议 `WebDAV`(`Web-based Distributed Authoring and Versioning`,基于万维网的分布式创作和版本控制)是一个可对 `Web` 服务器上的内容直接进行文件复制、编辑等操作的分布式文件系统(可在线修改文件的**网盘**)。 除了创建、删除文件等基本功能,它还具备文件创建者管理、文件编辑过程中禁止其他用户内容覆盖的加锁功能, 以及对文件内容修改的版本控制功能。 ![image-20200319140154332](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/95.png) 使用 `HTTP/1.1` 的 `PUT` 方法和 `DELETE` 方法, 就可以对 `Web `服务器上的文件进行创建和删除操作。 可是出于安全性及便捷性等考虑,一般不使用。 #### 1.WebDAV 内新增的方法及状态码 `WebDAV` 为实现远程文件管理,向 `HTTP/1.1` 中追加了以下这些方法。 | 方法 | 用途 | | :-------: | :------------: | | PROPFIND | 获取属性 | | PROPPATCH | 修改属性 | | MKCOL | 创建集合 | | COPY | 复制资源及属性 | | MOVE | 移动资源 | | LOCK | 资源加锁 | | UNLOCK | 资源解锁 | 新增状态码: | 状态码 | 含义 | | :---------------------: | :----------------------------------------------: | | 102 Processing | 可正常处理请求,但目前是处理中状态 | | 207 Multi-Status | 存在多种状态 | | 422 UnprocessibleEntity | 格式正确,内容有误 | | 423 Locked | 资源已被加锁 | | 424 FailedDependency | 处理与某请求关联的请求失败,因此不再维持依赖关系 | | 507 InsufficientStorage | 保存空间不足 | **WebDAV 的请求实例 ** 下面是使用 `PROPFIND` 方法对` http://www.example.com/file` 发起获取属性的请求 : ``` PROPFIND /file HTTP/1.1 Host: www.example.com Content-Type: application/xml; charset="utf-8" Content-Length: 219 //...请求主体 ``` **WebDAV 的响应实例 ** 下面是针对之前的 `PROPFIND` 方法, 返回`http://www.example.com/file `的属性的响应。 ``` HTTP/1.1 207 Multi-Status Content-Type: application/xml; charset="utf-8" Content-Length: 831 //...响应主体 ``` 不过可以使用`FTP`替代它; ## 十八、HTTP3.0 ![image-20200319142842312](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/96.png) #### 1.HTTP2.0的问题 * **队头阻塞**:由于只建立一个`TCP`连接,一旦出现某次传输出现丢包,就要等待重传,严重阻碍了其他数据的传输; * **建立连接的握手延迟大**:`HTTPS`和`HTTP2.0`除了建立`TCP`握手之外,还要建立`TSL`安全传输,这就出现了两次握手延迟;对于短连接来说,影响无法被移除,这些都是`TCP`的历史遗留问题; #### 2.QUIC的特性 * **0 RTP**:两层意思,建立`UDP`连接和建立`TSL`安全连接大多数情况只需要`0 RTP`; ![image-20200319143544308](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/97.png) * **没有队头阻塞的多路复用** 当`TCP`连接中传输的数据流`stream2`中出现丢包时,在发送端没有重传丢失的包之前跟在`stream2`后面的`stream3/4`就被阻塞住了; ![image-20200319143715846](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/98.png) 然而`UDP`连接中,数据流彼此间没有依赖关系,即使`stream2`出现丢包,也不影响其他`stream`数据的传输; ![image-20200319144040196](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/99.png) * **前向纠错**(`Front Error Collection`) 每个数据包除了它本身的数据之外,还包括了部分其他包的内容,因此少量的丢包可以通过其他包的冗余数据直接组装,而无需重传;这种方法虽然牺牲了每个数据包可发送数据的上限,但是减少了因为丢包导致的数据重传(更浪费时间);如果丢失的包过多,就只能通过重传来解决。 **QUIC**融合了`UDP`协议的速度性能和`TCP`的安全和可靠,大大优化了互联网传输数据的体验。 #### 3.HTTP协议总结 * `HTTP1.0/1.1`:有**连接无法复用**、**队头阻塞**、**协议开销大**和**安全因素**等多个缺点; * `HTTP2.0`:通过**多路复用**、**二进制流**、**头部压缩**等技术极大地提升了性能,但是还是存在问题; * `HTTP3.0`:`QUIC`是基于`UDP`实现的,是`HTTP3.0`的底层支持协议。该协议基于`UDP`又吸收了`TCP`的精华,实现了既快又可靠的连接; ## 十九、Web安全 ### 1.概述 **日常生活中的”安全“** * 为什么登录的时候经常要求我们输入一个验证码? * 在一个网站上长时间没有操作,为什么`Session`会失效? #### 1.1.WASC的定义 全程`Web Application Security Consortium`:是一个由安全专家、行业顾问和诸多组织的代表组成的国际团体,负责为`WWW`(万维网)制定广为人知的**应用安全标准**。 #### 1.2.六类Web应用安全威胁 | 名称 | 中文名 | 作用 | | :--------------------: | :--------: | :----------------------------------------------------------: | | Authentication | 验证 | 用来确认某用户、服务或是应用身份的攻击手段 | | Authorization | 授权 | 用来决定是否某用户、服务或是应用具有执行请求动作必要权限的攻击手段 | | Client-Side-Attacks | 客户侧攻击 | 用来扰乱或是探测`Web`站点用户的攻击手段 | | Command Execution | 命令执行 | 在`Web`站点上执行远程命令的攻击手段(比如`SQL`注入) | | Information Disclosure | 信息泄露 | 用来获取`Web`站点具体系统信息的攻击手段 | | Logical Attacks | 逻辑性攻击 | 用来扰乱或是探测`Web`应用逻辑流程的攻击手段 | #### 1.3.OWASP的定义 全称`Open Web Application Security Project`,该组织致力于发现和解决不安全`Web`应用的根本原因;它们最重要的项目之一是**Web应用的十大安全隐患** 总结了目前`Web`应用最常受到的十种攻击手段,并且按照攻击发生的概率进行了排序(以下为`2017`年的数据): | 排名 | 漏洞种类 | 详情 | | :--: | :--------------------: | :----------------------------------------------------------: | | A1 | 注入 | 将不受信任的数据作为命令或查询的一部分发送到解析器时,会产生注入:`SQL`注入、`NoSQL`注入、`OS`注入和`LDAP`注入缺陷。 | | A2 | 失效的身份认证 | 通过错误的使用应用程序的身份认证和会话管理功能,攻击者能够破译密码、密钥或会话令牌 | | A3 | 敏感数据泄露 | 许多`Web`程序和`API`都无法正确保护敏感数据,攻击者可通过窃取或修改未加密的数据来实施信用卡诈骗、身份盗窃等犯罪行为 | | A4 | XML外部实体(XXE) | 许多较早的或配置错误的`XML`处理器评估的`XML`文件中的外部实体引用。攻击者可利用外部实体窃取内部文件、执行远程代码 | | A5 | 失效的访问控制 | 未对通过身份验证的用户实施恰当的访问控制 | | A6 | 安全配置错误 | 安全配置错误是最常见的安全问题,这通常是由于不安全的默认配置、不完整的临时配置、开源云错误等造成 | | A7 | 跨站脚本(XSS) | `XSS`让攻击者能够在受害者的浏览器中执行脚本,并劫持用户会话、破坏网站或将用于重定向到恶意站点 | | A8 | 不完全的反序列化 | 不安全的反序列化会导致远程代码执行 | | A9 | 使用含有已知漏洞的组件 | 组件如库、框架和其他软件模块拥有和应用程序相同的权限 | | A10 | 不足的日志记录和监控 | 不足的日志记录和监控,以及事件响应缺失或无效的集成,使攻击者能够进一步攻击系统、保持持续性、篡改、提取或销毁数据 | ### 2.验证机制 验证机制是`Web`应用程序中最简单的一种**安全机制**,也是防御恶意攻击的**核心机制**; #### 2.1.典型的身份验证模式 ![image-20200319153857741](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/100.png) **验证技术** * 基于**HTML表单**的验证 * 多元机制,如组合密码; * 客户端`SSL`证书 **弱密码** 许多`Web`应用程序没有或很少对用户密码强度进行控制; **暴力破解** 登录功能的公开性会诱使**攻击者**试图**猜测**用户名和密码,从而获得访问应用程序的权力; **暴力破解-安全措施** * **验证码技术**:最常见和有效的应对方式,需要注意几个问题: * **验证码**是否真实有用 * 验证码的**复杂度**:从最开始的数字,到数字字母组合,再到谷歌奇形怪状的字母; * 应对当前的”**打码**“事业盛行:使用专门平台的”**打码**“服务器进行破解;对此出现了点击型的验证码、滑动型的验证码、问答型的验证码等更高级的验证码; * **Cookie和会话检测**:有些应用程序会设置一个**Cookie**,如`failedlogin = 0`;尝试登录失败,递增该值,达到某个上限,检测到这个值并拒绝再次处理登录; * 这样也不安全,只要客户端的`Cookie`在到达服务器端前被截获,就能被篡改; * **双因子认证**:双因子认证的核心是综合`What you know`(**个人密码**)和`What you have`(手机)来达到双重认证效果;(**较安全常用**) ### 3.会话管理机制 * 绝大多数`Web`应用程序中,会话管理机制是一个基本的**安全组件**。会话管理机制在应用程序执行登录功能时尤为重要,因为:它可以在用户通过请求提交它们的证书后,**持续向应用程序保证任何特定用户身份的真实性**; * 由于会话管理机制所发挥的关键作用,它们就成为了针对应用程序的**恶意攻击**的主要目标; * 若攻击者能够**破坏**应用程序的会话管理,他就能轻易避开其实施的验证机制,不需要用户证书即可伪装成其他应用程序用户。 #### 3.1.会话管理存在的漏洞 * **会话令牌生成漏洞**:比如采用常见的算法生成,容易被人猜出算法名称进行反编译破解; * **令牌可预测**:比如隐含序列,事件依赖; * **会话终止攻击**:会话结束后,**Cookie**没有真正意义上被删除,下次验证还有效; * **会话劫持攻击**:比如网络嗅探、`XSS`攻击等方式获取用户的会话令牌; #### 3.2.会话管理漏洞的防御 **令牌传输安全** * 令牌只能通过**HTTPS**传送; * 如果使用`HTTP cookie`传送令牌(大多数情况下)应该将`Cookie`字段标记为`Secure`,以防止用户浏览器通过`HTTP`传送它们; **增加软硬会话过期** * **软会话过期**:它指的是用户在一定的事件内与应用系统没有交互,则**会话过期**也就是我们常说的**Session失效**; * **硬会话过期**:它指的是用户登录到系统中经过一定的事件后,不管用户做什么,该会话都会过期(**网吧上网时间到了,强制下机**); ## 二十、常见的网络攻击 ### 1.SQL注入攻击 #### **1.1.SQL注入原理** * 几乎每个`Web`应用都需要使用**数据库**来保存操作所需要的各种信息; * 所以`Web`程序是经常会建立用户提交数据的`SQL`语句; * 最严重的情况下,攻击者可利用`SQL`注入,读取甚至修改数据库中保存的所有数据; * 用户可以提交一段**数据库查询代码**,根据程序返回结果,获得某些他想得知的数据; 这就是所谓的**SQL Injection**,即`SQL`注入;比如: ![c](https://gitee.com/ahuntsun/BlogImgs/raw/master/HTTP/HTTP%E7%9A%84%E5%89%8D%E4%B8%96%E4%BB%8A%E7%94%9F/101.png) 帐户名中输入的`‘or’1 = 1`会被识别为`SQL`操作指令; #### **1.2.SQL注入危害** * **探知数据库**的具体结构,为进一步攻击准备; * **泄露数据**,尤其是机密信息、账户信息等; * **取得更高权限**,用来修改数据甚至是内部结构; #### 1.3.SQL注入防御 **参数化查询** * **参数化查询**是对`SQL`注入根本性的**防御策略**,也叫做预处理语句,在建立一个包含用户输入的`SQL`语句时分为两步: * **指定查询结构,用户输入预留占位符;** * **指定占位符内容;** 比如使用问号`?`当作占位符,这样即使输入了`SQL`语句这样也不会被认为是数据`SQL`的一部分,而是用户输入内容。 **字符串过滤** **使用正则表达式过滤传入的参数** ### 2.跨域脚本攻击(XSS) 跨站脚本攻击(`Cross Site Scripting`),`XSS`(`CSS`已被占用所以叫`XSS`)是一种经常出现在`Web`应用中的计算机安全漏洞; 它允许`Web`用户恶意地将代码植入到提供给其他用户使用的页面中,其他用户在观看网页时,恶意脚本就会执行; #### 2.1.XSS攻击原理 * 这类攻击通常通过注入`HTML`或`JS`等脚本发动攻击; * 攻击成功后,攻击者可以得到私密网页内容和`Cookie`等; * 最近几年`XSS`攻击已成为最流行的攻击方式; #### 2.2.XSS攻击危害 * **盗取各类用户账号**:如机器登录账号、用户网银账号、各类管理员账号; * **控制数据**:包括读取、篡改、添加、删除企业敏感数据的能力; * 盗窃企业重要的具有**商业价值**的资料; * 非法转账; * 强制发送网站挂木马; * 控制受害者机器,让该用户成为"肉机",向其他网站发起攻击; #### 2.3.XSS攻击真实案例 > **Myspace XSS攻击事件** * 2005年,一名叫做`samy`的用户发现了`Myspace`(社交网站)的`XSS`漏洞,他在用户资料页面插入了一些`javascript`脚本; * 如果一个用户查看了他的用户资料,这段脚本就会被执行; * 脚本包括两方面:一是把`Samy`加为好友,二是将上面说的脚本复制到受害者自己的用户资料页面中; * 于是,所有查看受害者用户资料的用户也会成为受害者; * 一个基于存储式`XSS`攻击的蠕虫迅速扩散,几个小时内,`Samy`收到了近百万个好友的申请; * 为此,`Myspace`被迫关站,修复反`XSS`过滤机制并且从所有用户的资料中删除含有恶意脚本的内容; #### 2.4.XSS分类 针对`XSS`的攻击方式不同,可以把`XSS`分为如下三大类: * **反射式XSS** * **存储式XSS** * **基于DOM的XSS** ##### 反射式XSS 也称为**非永久性XSS**,目前最流行的`XSS`攻击;它出现在服务器直接服务器直接使用客户端提交的数据,如`URL`的数据、`HTML`表单中提交的数据,并且没有对数据进行无害化处理;如果提交的数据中含有`HTML`控制字符而没有被正确处理,那么一个简单的`XSS`攻击就会发生。 典型的反射式攻击方式可通过一个邮件或中间网站,诱饵是一个**看起来可信任**的站点的链接,其中包含`XSS`攻击脚本,比如社交群中常发的游戏活动、赌博、美女链接等。如果信任的网站没有正确处理这个脚本,用户点击后就会导致浏览器执行含有恶意攻击的脚本。 ##### 存储式XSS 也称为**永久性XSS**,危害更大。攻击将攻击脚本上传到`Web`服务器上,使得所有访问该页面的用户都面临信息泄露的可能,其中也包括了`Web`服务器的管理员; 存储式`XSS`多发生在最终显示给其他用户的位置包含: * 个人信息字段,如姓名、地址、电子邮件、电话等; * 文档、上传文件及其他数据的名称; * 提交给应用程序管理员的反馈或问题; * 向其他应用程序用户传送的消息、注释、问题等; * 在用户之间共享的上传文件内容; **典型的存储式XSS攻击过程** * 我拥有一个`Web`站点,该站点允许用户发布信息/浏览已发布信息; * 你注意到我的站点具有存储式的`XSS`漏洞; * 于是你发布一个热点信息,利用该漏洞获取用户信息,吸引其他用户纷纷阅读; * 任何其他人浏览该信息,其绘画`Cookies`或其他信息都会被你盗走; ##### 基于DOM的XSS攻击 反射式`XSS`攻击和存储式`XSS`攻击都是通过服务器提取用户提交的数据,并且以不安全的方式将其返回给用户;基于`DOM`的攻击仅仅通过`JavaScript`的方式执行; 也就是说这种攻击常发生在应用程序每次返回相同的静态页面(`HTML`文件),并通过客户端的`js`文件动态生成信息,并不会与服务器交互获取该`js`文件的时候; #### 2.5.XSS攻击载荷 **会话令牌** * `XSS`攻击对普遍的方式; * 截取一名受害者的会话令牌(`Token`),劫持他的会话,进而作为受害者的身份来使用应用程序,执行任意操作并占有该用户的账号; **虚拟置换** * 这种攻击需要在一个`Web`应用程序页面注入恶意数据,从而向应用程序的用户传送误导性信息; * 包括简单的向站点注入`HTML`,或者使用脚本注入精心设计的内容; 比如在淘宝的搜索结果页面中注入一个链接,受害者点击后跳转到一个和淘宝很像的钓鱼网页,登录时帐户信息就被泄露了; * 攻击者实际上没有修改保存在服务器上的内容,而是利用程序处理并显示用户提交的输入方面的缺陷实现置换; **注入木马** * 在一个明显的攻击中,攻击者注入的功能向用户显示一个木马登录表单,要求他们像攻击者控制的服务器提交他们自己的证书。 #### 2.6.XSS防御措施 ##### 输入验证 * 在输入的过程中,如果应用程序有向后端提交处理的数据,应**对这些数据进行严格的确认**; * 比如:数据不能太长; * 数据仅包含某组合法字符; * **数据与一个特殊的正则表达式匹配**(比如手机号); * 根据应用程序希望在每个字段中收到的数据类型,尽可能限制性地对姓名、电子邮件地址、账号等应用不同的确认规则; ##### 输出编码 * 如果应用程序将某位用户或第三方提交的数据复制到它的响应中,那么应用程序应对这些数据进行`HTML`编码,以净化可能的恶意字符; * `HTML`编码指用对应的`HTML`实体替代字面量字符。这样做可确保浏览器安全处理可能为恶意的字符,把它们当作`HTML`文档的内容而非结构处理; * 经常造成问题的字符的`HTML`编码: * `”` -> `"` * `'` -> `'` * `<` -> `<` * `>` -> `>` * `/` -> `x2F` 应用程序之所以结合使用**输入确认**(次要)与**输出净化**(首要),原因在于这种方法能够提供两层防御:如果其中一层被攻破,另一层还能提供一些保护; ### 3.CSRF攻击 `CSRF`(`Cross-site Request Forgery`)**跨站请求伪造**,也被称为`One Click Attack`或者`Session riding`通常缩写为`CSRF`或者`XSRF`,是一种对**网站的恶意利用**; 尽管听起来像跨站脚本(`XSS`),但它与`XSS`非常不同,并且攻击方式几乎相左; #### 3.1.CSRF攻击原理 * `XSS`利用站点内的**信任用户**(受害者),而`CSRF`通过伪装来自受信任用户的请求来利用**受信用的网站**; * 通过社会学的手段(如通过电子邮件发送一个链接)来蛊惑受害者进行一些敏感性的操作,如修改密码、修改`E-mail`、转账等,而受害者还不知道他已经中招; #### 3.2.CSRF攻击危害 * `CSRF`的**破坏力**依赖于**受害者**的**权限**; * 如果受害者只是个**普通用户**,则一个成功的`CSRF`攻击会危害用户的数据以及一些功能; * 如果受害者具有**管理员权限**,则一个成功的`CSRF`攻击甚至会威胁到整个网站的安全; * 与`XSS`攻击相比,`CSRF`攻击往往不太流行,因此对其进行防范的资源也相当稀少,和难以防范; * 故被认为比`XSS`更具危险性,所以`CSRF`在业内有个响当当的名字——**沉睡的巨人** #### 3.3.CSRF攻击的特点 - 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。 - 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。 - 整个过程攻击者**并不能**获取到受害者的登录凭证,仅仅是“冒用”。 - 跨站请求可以用各种方式:图片`URL`、超链接、`CORS`、`Form`提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。 `CSRF`通常是**跨域**的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。(比如博客留言) #### 3.4.CSRF攻击的过程 - 受害者登录`a.com`,并保留了登录凭证(`Cookie`); - 攻击者引诱受害者访问了`b.com`; - `b.com` 向` a.com` (服务器)发送了一个请求:`a.com/act=xx`。浏览器会默认携带`a.com`发放的`Cookie`; - `a.com`接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者(`a.com`的用户)自己发送的请求; - `a.com`以受害者的名义执行了`act=xx`; - 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让`a.com`执行了自己定义的操; #### 3.5.CSRF攻击预防 `CSRF`通常从第三方网站发起,被攻击的网站无法防止攻击发生,只能通过增强自己网站针对`CSRF`的防护能力来提升安全性。 上文中讲了`CSRF`的**两个特点**: - `CSRF`(通常)发生在第三方域名。 - `CSRF`攻击者不能获取到`Cookie`等信息,只是使用。 针对这两点,我们可以专门制定防护策略,如下: - **阻止不明外域的访问** - 同源检测 - `Samesite Cookie` - **提交时要求附加本域才能获取的信息** - `CSRF Token` - 双重`Cookie`验证 - 增加确认操作 - 重新认证 ##### 增加确认操作 * 比如转账功能,当用户调用`API`进行转装的时候,弹出一个对话框,例如:你确认转帐`200`元吗?即在浏览器上进行敏感操作时增加**确认操作**,**确保是用户所为**; ##### 重新认证 * 在做一些重要敏感的操作时,要求用户**重新输入密码**进入二次验证,只有正确了才进行操作;这种做法显然更安全,但对于用户来说不是特别友好——毕竟是增加了异一步操作; * 所以**安全和易用性**,有时候不得不做出取舍; ##### 使用Token* `CSRF`的一个特征是,攻击者无法直接窃取到用户的信息(`Cookie`,`Header`,网站内容等),仅仅是冒用`Cookie`中的信息。 而`CSRF`攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个`CSRF`攻击者无法获取到的`Token`。服务器通过校验请求是否携带正确的`Token`,来把正常的请求和攻击的请求区分开,也可以防范`CSRF`的攻击。 **验证过程** * 服务器端:在用户刚登陆的时候,产生一个新的不可预知的`CSRF Token`,并且把此`Token`存放在用户的`session`中。 * 在任何一个需要保护的表单中(转账,该密码),增加一个隐藏的字段来从服务器端获取和存放这个`Token`; * 提交请求的时候,在服务器端检查提交的`Token`与用户`Session`中的`Token`是否一致,如果一致,继续处理请求,不一致或者没有的话,就返回一个错误的信息给用户。 * 在用户退出或者`Session`过期的时候,用户信息(包括`CSRF Token`)从`Session`中移除并且销毁`Session`。 > 参考资料:[大话HTTP协议](https://coding.imooc.com/class/395.html)、《图解HTTP》、[前端安全系列之二:如何防止CSRF攻击?](https://www.cnblogs.com/meituantech/p/9777222.html)
加载全部内容