HTTP:报文,缓存,Cookie与HTTPS

当年HTTP协议的出现主要是为了解决文本传输的难题。1997年1月公布的HTTP/1.1是目前主流的HTTP协议版本。

HTTP方法

GET方法用来请求访问已被URI识别的资源。指定的资源经服务器端解析后返回响应内容。也就是说,如果请求的资源是文本,那就保持原样返回;如果是像CGI(Common Gateway Interface,通用网关接口)那样的程序,则返回经过执行后的输出结果。

POST方法用来传输实体的主体。

get和post区别:
get是以实体的方式得到由请求 URI 所指定资源的信息。
post方式: 用来向服务器发出请求,要求它接收被附在请求后的实体,并把它请求 URI 所指定资源的附加新子项,所以 post 请求可能会导致新的资源的建立和 / 或已有资源的修改。

PUT方法用来传输文件。在请求报文的主体中包含文件内容,然后保存到请求URI指定的位置。鉴于HTTP/1.1的PUT方法自身不带验证机制,一般的Web网站不使用该方法。

DELETE方法用来删除文件,是与PUT相反的方法。

HEAD方法和GET方法一样,只是不返回报文主体部分。用于确认URI的有效性及资源更新的日期时间等。使用GET方法时,对应请求资源的实体会作为响应返回;而使用HEAD方法时,对应请求资源的实体主体不随报文首部作为响应返回

TRACE方法是让Web服务器端将之前的请求通信环回给客户端的方法。发送请求时,在Max-Forwards首部字段中填入数值,每经过一个服务器端就将该数字减1,当数值刚好减到0时,就停止继续传输,最后接收到请求的服务器端则返回状态码200 OK的响应。客户端通过TRACE方法可以查询发送出去的请求是怎样被加工修改/篡改的。

CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL(Secure Sockets Layer,安全套接层)和TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。

HTTP报文

实体(entity)作为请求或响应的有效载荷数据(补充项)被传输。通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。

常用的内容编码有以下几种。
●gzip(GNU zip)
●compress(UNIX系统的标准压缩)
●deflate(zlib)
●identity(不进行编码)

断点重传:从之前下载中断处恢复下载。要实现该功能需要指定下载的实体范围。像这样,指定范围发送的请求叫做范围请求(Range Request)。执行范围请求时,会用到首部字段Range来指定资源的byte范围。针对范围请求,响应会返回状态码为206 Partial Content的响应报文。如果服务器端无法响应范围请求,则会返回状态码200 OK和完整的实体内容。

内容协商:指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。
●Accept-Charset
●Accept-Encoding
●Accept-Language
●Content-Language

通用首部字段

首部字段Upgrade用于检测HTTP协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议。使用首部字段Upgrade时,还需要额外指定Connection:Upgrade。
对于附有首部字段Upgrade的请求,服务器可用101 Switching Protocols状态码作为响应返回。

如为了实现WebSocket通信,在HTTP连接建立之后,需要完成一次“握手”(Handshaking)的步骤

使用首部字段Via是为了追踪客户端与服务器之间的请求和响应报文的传输路径。
报文经过代理或网关时,会先在首部字段Via中附加该服务器的信息,然后再进行转发。

请求首部字段

Accept: text/html,application/xhtml+xml,application/xml;q=0.9
使用q=来额外表示权重值,当服务器提供多种内容时,将会首先返回权重值最高的媒体类型。

首部字段Authorization是用来告知服务器,用户代理的认证信息(证书值)。通常,想要通过服务器认证的用户代理会在接收到返回的401状态码响应后,把首部字段Authorization加入请求中。

Host首部字段在HTTP/1.1规范内是唯一一个必须被包含在请求内的首部字段。

在GET或HEAD方法中使用首部字段If-None-Match可获取最新的资源。

通过TRACE方法或OPTIONS方法,发送包含首部字段Max-Forwards的请求时,该字段以十进制整数形式指定可经过的服务器最大数目。

首部字段User-Agent会将创建请求的浏览器和用户代理名称等信息传达给服务器。

响应首部字段

首部字段ETag能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的ETag值。另外,当资源更新时,ETag值也需要更新。

  • 强ETag值,不论实体发生多么细微的变化都会改变其值。
  • 弱ETag值只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变ETag值。这时,会在字段值最开始处附加W/。

首部字段WWW-Authenticate用于HTTP访问认证。它会告知客户端适用于访问请求URI所指定资源的认证方案(Basic或是Digest)和带参数提示的质询(challenge)。状态码401 Unauthorized响应中,肯定带有首部字段WWW-Authenticate。

实体首部字段

首部字段Allow用于通知客户端能够支持Request-URI指定资源的所有HTTP方法。当服务器接收到不支持的HTTP方法时,会以状态码405 Method Not Allowed作为响应返回。与此同时,还会把所有能支持的HTTP方法写入首部字段Allow后返回。

状态码

如200 OK,以3位数字和原因短语组成。

https://tool.lu/httpcode/ 这个网站还蛮有意思的

204 No Content
服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用。

206 Partial Content
客户端进行了范围请求,而服务器成功执行了这部分的GET请求。响应报文中包含由Content-Range指定范围的实体内容。

301 Moved Permanently
永久性重定向。如果已经把资源对应的URI保存为书签了,这时应该按Location首部字段提示的URI重新保存。

302 Found
临时性重定向。该状态码表示请求的资源已被分配了新的URI,希望用户(本次)能使用新的URI访问。

303 See Other
由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源。

当301、302、303响应状态码返回时,几乎所有的浏览器都会把POST改成GET,并删除请求报文内的主体,之后请求会自动再次发送。

304 Not Modified
304虽然被划分在3XX类别中,但是和重定向没有关系。
该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回304 Not Modified(服务器端资源未改变,可直接使用客户端未过期的缓存)。304状态码返回时,不包含任何响应的主体部分。
附带条件的请求是指采用GET方法的请求报文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部。

307 Temporary Redirect
临时重定向。该状态码与302 Found有着相同的含义。307会遵照浏览器标准,不会从POST变成GET。

400 Bad Reques
该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。

401 Unauthorized
该状态码表示发送的请求需要有通过HTTP认证(BASIC认证、DIGEST认证)的认证信息。另外若之前已进行过1次请求,则表示用户认证失败。

403 Forbidden
该状态码表明对请求资源的访问被服务器拒绝了。

500 Internal Server Error
该状态码表明服务器端在执行请求时发生了错误。也有可能是Web应用存在的bug或某些临时的故障。

503 Service Unavailable
该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入Retry-After首部字段再返回给客户端。

缓存

缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。

当判定缓存过期后,会向源服务器确认资源的有效性。

通过指定首部字段Cache-Control的指令,就能操作缓存的工作机制。

缓存请求指令

缓存响应指令

使用no-cache指令的目的是为了防止从缓存中返回过期的资源。

从字面意思上很容易把no-cache误解成为不缓存,但事实上no-cache代表不缓存过期的资源,缓存会向源服务器进行有效期确认后处理资源,也许称为do-not-serve-from-cache-without-revalidation更合适。no-store才是真正地不进行缓存

当使用no-store指令时,暗示请求(和对应的响应)或响应中包含机密信息。因此,该指令规定缓存不能在本地存储请求或响应的任一部分。

当客户端发送的请求中包含max-age指令时,如果判定缓存资源的缓存时间数值比指定时间的数值更小,那么客户端就接收缓存的资源。另外,当指定max-age值为0,那么缓存服务器通常需要将请求转发给源服务器。
当服务器返回的响应中包含max-age指令时,缓存服务器将不对资源的有效性再作确认,而max-age数值代表资源保存为缓存的最长时间。

min-fresh指令要求缓存服务器返回至少还未过指定时间的缓存资源。

使用max-stale可指示缓存资源,即使过期也照常接收。

使用only-if-cached指令表示客户端仅在缓存服务器本地缓存目标资源的情况下才会要求其返回。换言之,该指令要求缓存服务器不重新加载响应,也不会再次确认资源有效性。若发生请求缓存服务器的本地缓存无响应,则返回状态码504 Gateway Timeout

使用must-revalidate指令,代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效。
若代理无法连通源服务器再次获取有效资源的话,缓存必须给客户端一条504(Gateway Timeout)状态码。

使用no-transform指令可防止缓存或代理压缩图片等类似操作。

HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。每当有新的请求发送时,就会有对应的新响应产生。这是为了更快地处理大量事务,确保协议的可伸缩性。为了实现期望的保持状态功能,于是引入了Cookie技术。

Cookie会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值后发送出去。
<Set-Cookie: sid=1342077140226724; path=/; expires=Wed, => 10-Oct-12 07:12:20 GMT>
服务器端发现客户端发送过来的Cookie后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。
Cookie: sid=1342077140226724

Set-Cookie的字段值

一旦Cookie从服务器端发送至客户端,服务器端就不存在可以显式删除Cookie的方法。但可通过覆盖已过期的Cookie,实现对客户端Cookie的实质性删除操作。

HttpOnly属性是Cookie的扩展功能,它使JavaScript脚本无法获得Cookie。其主要目的为防止跨站脚本攻击(Cross-site scripting,XSS)对Cookie的信息窃取。

Session管理

基于表单认证本身是通过服务器端的Web应用,会使用Cookie来管理Session
步骤1: 客户端把用户ID和密码等登录信息放入报文的实体部分,通常是以POST方法把请求发送给服务器。而这时,会使用HTTPS通信来进行HTML表单画面的显示和用户输入数据的发送。
步骤2: 服务器会发放用以识别用户的Session ID。通过验证从客户端发送过来的登录信息进行身份认证,然后把用户的认证状态与Session ID绑定后记录在服务器端。
向客户端返回响应时,会在首部字段Set-Cookie内写入Session ID(如PHPSESSID=028a8c…)。
为减轻跨站脚本攻击(XSS)造成的损失,建议事先在Cookie内加上httponly属性
步骤3: 客户端接收到从服务器端发来的Session ID后,会将其作为Cookie保存在本地。下次向服务器发送请求时,浏览器会自动发送Cookie,所以Session ID也随之发送到服务器。服务器端可通过验证接收到的Session ID识别用户和其认证状态。

HTTPS

HTTP+加密+认证+完整性保护=HTTPS

HTTP主要有这些不足,例举如下。
●通信使用明文(不加密),内容可能会被窃听
●不验证通信方的身份,因此有可能遭遇伪装,DoS攻击(Denial of Service,拒绝服务攻击)
●无法证明报文的完整性,所以有可能已遭篡改,中间人攻击(Man-in-the-Middle attack,MITM)

HTTP协议中没有加密机制,但可以通过和SSL(Secure Socket Layer,安全套接层)或TLS(Transport Layer Security,安全传输层协议)的组合使用,加密HTTP的通信内容。

SSL位于表示层

SSL采用一种叫做公开密钥加密(Public-key cryptography)的加密处理方式。公开密钥加密使用一对非对称的密钥。

HTTPS采用共享密钥加密和公开密钥加密两者并用的混合加密机制。在交换密钥环节使用公开密钥加密方式,之后的建立通信交换报文阶段则使用共享密钥加密方式。

SSL不仅提供加密处理,而且还使用了一种被称为证书的手段,可用于确定方。证书由值得信任的第三方机构颁发,用以证明服务器和客户端是实际存在的。

HTTPS的通信步骤

步骤1: 客户端通过发送Client Hello报文开始SSL通信。报文中包含客户端支持的SSL的指定版本、加密组件(Cipher Suite)列表(所使用的加密算法及密钥长度等)。
步骤2: 服务器可进行SSL通信时,会以Server Hello报文作为应答。和客户端一样,在报文中包含SSL版本以及加密组件。服务器的加密组件内容是从接收到的客户端加密组件内筛选出来的。
步骤3: 之后服务器发送Certificate报文。报文中包含公开密钥证书。
步骤4: 最后服务器发送Server Hello Done报文通知客户端,最初阶段的SSL握手协商部分结束。
步骤5: SSL第一次握手结束之后,客户端以Client Key Exchange报文作为回应。报文中包含通信加密中使用的一种被称为Pre-master secret的随机密码串。该报文已用步骤3中的公开密钥进行加密。
步骤6: 接着客户端继续发送Change Cipher Spec报文。该报文会提示服务器,在此报文之后的通信会采用Pre-master secret密钥加密。
步骤7: 客户端发送Finished报文。该报文包含连接至今全部报文的整体校验值。这次握手协商是否能够成功,要以服务器是否能够正确解密该报文作为判定标准。
步骤8: 服务器同样发送Change Cipher Spec报文。
步骤9: 服务器同样发送Finished报文。
步骤10: 服务器和客户端的Finished报文交换完毕之后,SSL连接就算建立完成。当然,通信会受到SSL的保护。从此处开始进行应用层协议的通信,即发送HTTP请求。
步骤11: 应用层协议通信,即发送HTTP响应。
步骤12: 最后由客户端断开连接。断开连接时,发送close_notify报文。

在以上流程中,应用层发送数据时会附加一种叫做MAC(Message Authentication Code)的报文摘要。MAC能够查知报文是否遭到篡改,从而保护报文的完整性。

既然HTTPS那么安全可靠,那为何所有的Web网站不一直使用HTTPS?

  • 使用HTTP相比,网络负载可能会变慢2到100倍
  • 加密通信会消耗更多的CPU及内存资源
  • 想要节约购买证书的开销