图解 HTTP 笔记

1. 了解Web及网络基础

1.1 使用HTTP协议访问Web

Web浏览器根据地址栏中指定的URL, 从Web服务器端获取文件资源等信息, 从而显示出Web页面. Web使用HTTP(HyperText Transfer Protocol, 超文本传输协议)作为规范. (HTTP严谨的译名叫”超文本转移协议”)

1.2 HTTP的诞生

CERN(欧洲核子研究组织)的Tim Berners-Lee博士提出了一种能让远隔两地的研究者们共享知识的设想, 最初设想的基本理念是: 借助多文档之间相互关联形成的超文本(HyperText), 连成可相互参阅的WWW(World Wide Web, 万维网).
现在已提出了3项WWW构建技术:

  • 把SGML(Standard Generalized Markup Language, 标准通用标记语言)作为页面的文本标记语言的HTML.
  • 作为文档传输协议的HTTP.
  • 指定文档所在地址的URL(Uniform Resource Locator, 统一资源定位符)

1995年左右, 微软公司和网景通信公司之间爆发了浏览器大战, 两家公司的浏览器(微软的Internet Explorer和网景的Netscape Navigator)都各自对HTML做了扩展, 导致了后续的前端页面工程师写HTML页面时必须考虑兼容他们这两家公司的浏览器. 2000年前后这场战争随着网景公司的衰落而暂告一段落. 但2004年Mozilla基金会发布了Firefox浏览器, 第二次浏览器大战随即爆发.

1.3 网络基础TCP/IP

TCP/IP协议族按层次分别分为以下4层:

  • 应用层: 决定了向用户提供应用服务时通信的活动. FTP, DNS, HTTP等.
  • 传输层: 提供处于网络连接中的两台计算机之间的数据传输. TCP, UDP.
  • 网络层: 处理在网络上流动的数据包(网络传输的最小数据单位).
  • 数据链路层: 用来处理连接网络的硬件部分.

1.4 与HTTP关系密切的协议:IP, TCP和DNS

IP(Internet Protocol)网际协议位于网络层. Internet Protocol这个名字听起来这么高大上, 但事实确实是如此, 因为几乎所有使用网络的系统都会用到IP协议. 有时候我们会把”IP”和”IP地址”搞混淆.

使用ARP协议凭借MAC地址进行通信

IP间的通信依赖MAC地址, 而ARP(Address Resolution Protocol)协议能根据通信方的IP地址就可以查出对应的MAC地址.

确保可靠性的TCP协议

TCP位于传输层, 提供可靠的字节流服务(Byte Stream Service), 它将大块数据分割成报文段(segment)为单位的数据包进行管理. TCP采用三次握手(three-way handshaking)策略, 握手过程中使用了TCP的标志(flag)–SYN(synchronize)和ACK(acknowledge).

1.5 负责域名解析的DNS服务

DNS(Domain Name System)服务是和HTTP协议一样位于应用层的协议, 它提供域名到IP地址之间的解析服务.

1.6 各种协议与HTTP协议的关系

客户端想浏览某个页面:
1.首先是将域名用DNS解析返回服务器的IP地址.
2.HTTP协议的职责就是, 生成针对目标Web服务器的HTTP请求报文.
3.TCP协议将该HTTP请求报文按序号分割成报文段, 把每个报文段可靠地传给对方.
4.IP协议的职责就是搜索对方的地址, 一边中转一边传送.
5.TCP从对方那里接收报文段, 按序号重组到达的报文段.
6.HTTP协议的职责, 对Web服务器请求的内容处理.
最后请求的处理结果也同样利用TCP/IP通信协议向用户进行回传.

1.7 URI和URL

1.7.1 统一资源标识符

URI是Uniform Resource Identifier的缩写. RFC2396分别对这三个单词进行了定义:

  • Uniform: 规定统一的格式可以方便处理多种不同类型的资源.
  • Resource: 资源的定义是”可标识的任何东西”, 可以是单一的也可以是多数的集合体.
  • Identifier: 表示可标识的对象, 也称为标识符.

URI就是由某个协议方案表示的资源的定位标识符. 采用HTTP协议时, 协议方案就是http. 还有ftp, mailto, telnet, file等30多种标准的URI协议方案. 这些方案由ICANN的IANA管理发布.

URI用字符串标识某一互联网资源, 而URL表示资源的地点, URL是URI的子集.

1.7.2 URI格式

绝对URI格式:

2.简单的HTTP协议

2.1 HTTP协议用于客户端和服务端之间的通信

2.2 通过请求和响应的交换达成通信

请求报文示例:

1
2
GET /index.htm HTTP/1.1
Host: hackr.jp
  • 起始行开头的GET表示请求访问服务器的类型, 称为方法(method).
  • 字符串/index.htm指明了请求访问的资源对象, 也叫请求URI(request-URI).
  • 最后的HTTP/1.1是HTTP的版本号.

这段请求内容的意思是: 请求访问某台HTTP服务器上的/index.htm页面资源.

请求报文是由请求方法, 请求URI, 协议版本, 可选的请求首部字段和内容实体构成.

接收到请求的服务器, 会将请求内容的处理结果以响应的形式返回:

1
2
3
4
5
6
7
HTTP/1.1 200 OK
Data: Tue, 10 Jul 2012 06:50:15 GMT
Content-Length: 362
Content-Type: text/html

<html>
......

起始行开头的HTTP/1.1表示服务器对应的HTTP版本.
紧挨着的200 OK表示请求的处理结果的状态码(status code)和原因短语(reason-phrase). 下一行显示了创建响应的日期时间, 是首部字段(header field)内的一个属性.
接着以一空行分隔, 之后的内容称为资源实体的主体(entity body).

响应报文基本上由协议版本, 状态码, 解释状态码的原因短语, 可选的响应首部字段以及实体主体构成.

2.3 HTTP是不保存状态的协议

HTTP/1.1虽然是无状态协议, 但是为了实现期望的保持状态功能, 于是引入了Cookie技术.

2.4 请求URI定位资源

当客户端请求访问资源而发送请求时, URI需要将作为请求报文中的请求URI包含在内.

除此之外, 如果不是访问特定资源而是对服务器本身发起请求, 可以用一个*来代替请求URI.

1
OPTIONS * HTTP/1.1

2.5 告知服务器意图的HTTP方法

GET: 获取资源

GET方法用来请求访问已被URI识别的资源, 指定的资源经服务器解析后返回相应内容.

POST: 传输实体主体

POST的功能与GET很相似, 但POST的主要目的并不是获取响应的主题内容.

PUT: 传输文件

PUT方法用来传输文件. (方法自身不带验证机制, 因此一般Web网站不使用该方法…平常自己项目传文件用POST都可以)

HEAD: 获得报文首部

HEAD方法和GET方法一样, 只是不返回报文的主体部分. 用于确认URI的有效性及资源更新的日期时间等.

DELETE: 删除文件

和PUT差不多.

OPTIONS: 询问支持的方法

OPTIONS方法用来查询针对请求URI指定的资源支持的方法.

TRACE: 追踪路径

客户端通过TRACE方法可以查询发送出去的请求是怎样被加工修改/篡改的. 这是因为, 请求想要连接到源目标服务器可能会通过代理中转, TRACE方法就是用来确认连接过程中发生的一系列操作.
但TRACE本来不怎么常用, 它容易引发XST攻击, 通常就更不会用到了.

CONNECT: 要求用隧道协议连接代理

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

CONNECT方法的格式如下:

1
CONNECT 代理服务器名:端口号 HTTP版本

2.6 使用方法下达命令

2.7 持久连接节省通信量

2.7.1 持久连接

为解决每进行一次HTTP通信就要断开一次TCP连接问题, 提出了持久连接(HTTP Persistent Connections, 也称为HTTP keep-alive或者HTTP connection reuse)的方法. 其特点是, 只要任意一端没有明确提出断开连接, 则保持TCP连接状态.

2.7.2 管线化

持久连接使得多数请求以管线化(pipelining)方式发送成为可能. 管线化技术出现后, 不用等待响应亦可直接发送下一个请求. 这样就能够做到同时并发发送多个请求, 而不需要一个接一个地等待响应了.

2.8 使用Cookie的状态管理

1.–>请求报文(没有Cookie信息的状态)
2.<–响应报文(服务端生成Cookie信息, 并设置Set-Cookie首部字段信息, 让客户端保存Cookie)
3.–>请求报文(自动发送保存着的Cookie信息)

3. HTTP报文内的HTTP信息

3.1 HTTP报文

HTTP报文大致可分为报文首部和报文主体两块. 中间以最初出现的空行(CR+LF)来划分. 并不一定要有报文主体.

3.2 请求报文及响应报文的结构

报文首部又由请求行, 状态行, 首部字段, 其它组成.

3.3 编码提升传输速率

3.3.1 报文主体和实体主体的差异

通常这两者是相等的. 但如果传输时进行了编码操作, 那么编码后的实体主体和报文主体就长得不相同了.

3.3.2 压缩传输的内容编码

常用的内容编码:

  • gzip (GNU zip)
  • compress (UNIX系统的标准压缩)
  • deflate (zlib)
  • identity (不进行编码)
  • brotli (2015年后新兴)

3.3.3 分割发送的分块传输编码

在传输大容量数据时, 通过把数据分割成多块, 能够让浏览器逐步显示页面. 这种把实体主体分块的功能称为分块传输编码(Chunked Transfer Coding).

3.4 发送多种数据的多部分对象集合

HTTP协议中也采纳了多部分对象集合, 发送的一份报文主体内可含有多类型实体.
多部分对象集合包含的对象:

  • multipart/form-data: 在Web表单文件上传时使用
  • multipart/byteranges: 状态码206(Partial Content, 部分内容)响应报文包含了多个范围的内容时使用.

使用boundary字符串来划分多个部分对象集合指明的各类实体.

3.5 获取部分内容的范围请求

要实现从之前下载中断处恢复下载功能, 需要指定下载的实体范围, 像这样, 指定范围发送的请求叫做范围请求(Range Request).

3.6 内容协商返回最合适的内容

也就是客户端期望接收怎么样的网页(例如不同语言). 主要有服务器协商, 客户端协商, 透明协商(也就是前两者的结合)方式.

4. 返回结果的HTTP状态码

4.1 状态码告知从服务器端返回的请求结果

4.2 2XX成功

2XX的响应结果表明请求被正常处理了.

4.3 3XX重定向

3XX响应结果表明浏览器需要执行某些特殊的处理以正确处理请求.

4.4 4XX客户端错误

4XX的响应结果表明客户端是发生错误的原因所在.

4.5 5XX服务器错误

5XX的响应结果表明服务器本身发生错误.

5. 与HTTP协作的Web服务器

5.1 用单台虚拟主机实现多个域名

这种情况下多个域名会在相同的IP地址下, 因此在返回该HTTP请求响应时, 必须在Host首部内完整指定主机名或域名的URI.

5.2 通信数据转发程序: 代理, 网关, 隧道

5.2.1 代理

每次通过代理服务器转发请求或响应时, 会追加写入Via首部信息.

  • 缓存代理(Caching Proxy)
  • 透明代理(Transparent Proxy): 不对报文做任何加工.

5.2.2 网关

网关的工作机制和代理十分相似. 而网关能使通信线路上的服务器提供非HTTP协议服务.

5.2.3 隧道

隧道可按要求建立起一条与其它服务器的通信线路, 届时使用SSL等加密手段进行通信. 隧道的目的是确保客户端能与服务器进行安全的通信. 隧道本身不会去解析HTTP请求. 也就是说, 请求保持原样中转给之后的服务器. 隧道会在通信双方断开连接时结束.

5.3 保存资源的缓存

5.3.1 缓存的有效期限

5.3.2 客户端的缓存

6. HTTP首部

6.1 HTTP报文首部

6.2 HTTP首部字段

6.2.1 HTTP首部字段传递重要信息

使用首部字段是为了给浏览器和服务器提供报文主体大小, 所使用的语言, 认证信息等内容.

6.2.2 HTTP首部字段结构

HTTP首部字段是由首部字段名和字段值构成的, 中间用冒号”:”分隔.

6.2.3 4种HTTP首部字段类型

根据实际用途分为以下4类:

  • 通用首部字段(General Header Fields): 请求报文和响应报文都会使用的首部.
  • 请求首部字段(Request Header Fields): 补充了请求的附加内容, 客户端信息, 相应内容相关优先级等信息.
  • 响应首部字段(Response Header Fields): 补充了响应的附加内容, 也会要求客户端附加额外的内容信息.
  • 实体首部字段(Entity Header Fields): 针对实体部分的首部, 补充了资源内容更新时间等与实体有关的信息.

6.2.4 HTTP/1.1首部字段一览

6.2.5 非HTTP/1.1首部字段

在HTTP协议通信交互中使用到的首部字段, 不限于RFC2616中定义的47种首部字段. 还有Cookie, Set-Cookie和Content-Disposition等在其它RFC中定义的首部字段, 它们的使用频率也很高. 这些非正式的首部字段统一归纳在RFC4229 HTTP Header Field Registrations中.

6.2.6 End-to-end 首部和Hop-by-hop首部

HTTP首部字段将定义成缓存代理和非缓存代理的行为(也就是说缓存是否保存和转发这些首部), 分为2种类型:

  • 端到端首部(End-to-end Header): 这一类首部会转发给请求/响应的最终接收目标, 且必须保存在由缓存生成的响应中, 它必须被转发.
  • 逐跳首部(Hop-by-hop Header): 分在此类别中的首部只对单次转发有效, 会因通过缓存或代理而不再转发. HTTP/1.1和之后版本中, 如果要使用hop-by-hop首部, 需提供Connection首部字段.

下面列举了HTTP/1.1中的逐跳首部字段. 除了这8个首部字段之外, 其他所有字段都属于端到端首部.

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • Trailer
  • TE
  • Transfer-Encoding
  • Upgrade

更多参阅HTTP协议的Connection头

6.3 HTTP/1.1通用首部字段

6.3.1 Cache-Control

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

6.3.2 Connection

Connection首部字段具备如下两个作用:

  • 控制不再转发给代理的首部字段
  • 管理持久连接

控制不再转发给代理的首部字段

1
Connection: 不再转发的首部字段名

此时代理服务器转发时, 将删除对应字段再转发. 也就是Hop-by-hop首部.

管理持久连接

HTTP/1.1版本的默认连接都是持久连接. 因此, 客户端会在持久连接上连续发送请求. 当服务器端想明确断开连接时, 则指定Connection首部字段的值为Close.

6.3.3 Date

首部字段Date表明创建HTTP报文的日期和时间.

6.3.4 Pragma

Pragma是HTTP/1.1之前版本的历史遗留字段, 仅作为与HTTP/1.0的向后兼容而定义.

6.3.5 Trailer

首部字段Trailer会事先说明在报文主体后记录了哪些首部字段. (就是把字段放在主体, 一般把动态生成的内容放这里, 比如消息的完整性校验, 数字签名之类)

6.3.6 Transfer-Encoding

首部字段Transfer-Encoding规定了传输报文主体时采用的编码方式.

6.3.7 Upgrade

首部字段Upgrade用于检测HTTP协议以及其他协议是否可使用更高的版本进行通信, 其参数值可以用来指定一个完全不同的通信协议. 但是Upgrade对象仅限于客户端和邻接服务器之间, 因此除了首部字段Upgrade, 还得额外指定Connection: Upgrade字段和值.

6.3.8 Via

使用首部字段Via是为了追踪客户端与服务器之间的请求和响应报文的传输路径. 首部字段Via不仅用于追踪报文的转发, 还可避免请求回环的发生, 所以必须在经过代理时附加该首部字段内容.
Via首部是为了追踪传输路径, 所以经常会和TRACE方法一起使用. 比如, 代理服务器接收到由TRACE方法发送过来的请求(其中Max-Forwards: 0)时, 代理服务器就不能再转发该请求了. 这种情况下, 代理服务器会将自身的信息附加到Via首部后, 返回该请求的响应.

6.3.9 Warning

HTTP/1.1的Warning首部是从HTTP/1.0的响应首部(Retry-After)演变过来的. 该首部通常会告知用户一些与缓存相关的问题的警告.

6.4 请求首部字段

6.4.1 Accept

Accept首部字段可通知服务器, 用户代理能够处理的媒体类型及媒体类型的相对优先级. 可使用type/subtype这种形式, 一次指定多种媒体类型. 可以使用q=来额外表示权重值, 用分号;进行分隔. 权重值范围是0~1, 1为最大值. 服务器会首先返回权重值最高的媒体类型.

6.4.2 Accept-Charset

Accept-Charset首部字段可用来通知服务器用户代理支持的字符集及字符集的相对优先顺序.

6.4.3 Accept-Encoding

Accept-Encoding首部字段用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序.
另外, 也可使用星号(*)作为通配符, 指定任意的编码格式.

6.4.4 Accept-Language

和上面差不多, 这个是语言相关.

6.4.5 Authorization

通常, 想要通过服务器认证的用户代理会在接收到返回的401状态码响应后, 把首部字段Authorization加入请求中.

6.4.6 Expect

1
Expect: 100-continue

目的是, 在客户端发送Request Message之前, HTTP/1.1协议允许客户端先判定服务器是否愿意接受客户端发来的消息主体(基于Request Headers).

6.4.7 From

首部字段From用来告知服务器使用用户代理的用户的电子邮件地址. 通常, 其使用目的就是为了显示搜索引擎等用户代理的负责任的电子邮件联系方式.

6.4.8 Host

首部字段Host会告知服务器, 请求的资源所处的互联网主机名和端口号. Host首部字段在HTTP/1.1规范内是唯一一个必须被包含在请求内的首部字段.(值可以为空哈哈哈)

首部字段Host和以单台服务器分配多个域名的虚拟主机的工作机制有很密切的关联, 这是首部字段Host必须存在的意义.

6.4.9 If-Match

形如If-xxx这种样式的请求首部字段, 都可称为条件请求. 服务器接收到附带条件的请求后, 只有判断指定条件为真时, 才会执行请求.

6.4.10 If-Modified-Since

If-Modified-Since用于确认代理或客户端拥有的本地资源的有效性.

6.4.11 If-None-Match

它和首部字段If-Match作用相反. 用于指定If-None-Match字段值的实体标记值与请求资源的ETag不一致时, 它就告知服务器处理该请求.
在GET或HEAD方法中使用首部字段If-None-Match可获取最新的资源. 因此这与使用首部字段If-Modified-Since时有些类似.

6.4.12 If-Range

首部字段If-Range告知服务器若指定的If-Range字段值(ETag值或者时间)和请求资源的ETag值或时间相一致时, 则作为范围请求处理. 反之, 则返回全体资源.

6.4.13 If-Unmodified-Since

首部字段If-Unmodified-Since和首部字段If-Modified-Since的作用相反. 它的作用的目的是告知服务器, 指定的请求资源只有在字段值内指定的日期时间之后, 未发生更新的情况下, 才能处理请求.

6.4.14 Max-Forwards

通过TRACE方法或者OPTIONS方法, 发送包含首部字段Max-Forwards的请求时, 该字段以十进制整数形式指定可经过的服务器最大数目. 服务器在往下一个服务器转发请求之前, Max-Forwards的值减1后重新赋值. 当服务器接收到Max-Forwards值为0的请求时, 则不再进行转发, 而是直接返回响应.

使用HTTP协议通信时, 请求可能会经过代理等多台服务器. 途中, 如果代理服务器由于某些原因导致请求转发失败, 客户端也就等不到服务器返回的响应了. 对此, 我们无从可知.

可以灵活使用首部字段Max-Forwards, 针对以上问题产生的原因展开调查. 由于当Max-Forwards字段值为0时, 服务器就会立即返回响应, 由此我们至少可以对以那台服务器为终点的传输路径的通信状况有所把握.

6.4.15 Proxy-Authorization

客户端接收到从代理服务器发来的认证质询时, 客户端会发送包含首部字段Proxy-Authorization的请求, 以告知服务器认证所需要的信息.

6.4.16 Range

对于只获取部分资源的范围请求, 包含首部字段Range即可告知服务器资源的执行范围.

6.4.17 Referer

首部字段Referer会告知服务器请求的原始资源的URI.(就是客户端原来想请求啥东西) 出于安全性的考虑有时候也可也不发这个首部.

6.4.18 TE

首部字段TE会告知服务器客户端能够处理响应的传输编码方式及相对优先级.

首部字段TE除指定传输编码之外, 还可以指定伴随trailer字段的分块传输编码的方式. 应用后者时, 只需把trailers赋值给该字段值.

1
TE: trailers

6.4.19 User-Agent

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

由网络爬虫发起请求时, 有可能会在字段内添加爬虫作者的电子邮件地址. 如果请求经过代理, 那么中间也很可能被添加上代理服务器的名称.

6.5 响应首部字段

6.5.1 Accept-Ranges

首部字段Accept-Ranges是用来告知客户端服务器是否能处理范围请求, 以指定获取服务器某个部分的资源.

6.5.2 Age

首部字段Age能告知客户端, 源服务器在多久前创建了响应, 字段值的单位为秒. 代理创建响应时必须加上首部字段Age.

6.5.3 ETag

首部字段ETag能告知客户端实体标识. 它是一种可将资源以字符串形式做唯一性标识的方式. 服务器会为每份资源分配对应的ETag值.

另外, 当资源更新时, ETag值也需要更新. 生成ETag值时, 并没有统一的算法规则, 而仅仅是由服务器来分配.

ETag中有强ETag值和弱ETag值之分. 强ETag值不论实体发生多么细微的变化都会改变其值. 弱ETag值只用于提示资源是否相同, 只有资源发生了根本改变, 产生差异时才会改变ETag值.

6.5.4 Location

使用首部字段Location可以将响应接收方引导至某个与请求URI位置不同的资源.

基本上, 该字段会配合3xx:Redirection的响应, 提供重定向的URI.

几乎所有的浏览器在接收到包含首部字段Location的响应后, 都会强制性地尝试对已提示的重定向资源的访问.

6.5.5 Proxy-Authenticate

首部字段Proxy-Authenticate会把由代理服务器所要求的认证信息发送给客户端.

6.5.6 Retry-After

首部字段Retry-After告知客户端应该在多久之后再次发送请求.

6.5.7 Server

首部字段Server告知客户端当前服务器上安装的HTTP服务器应用程序的信息. 不单单会标出服务器上的软件应用名称, 还有可能包括版本号和安装时启用的可选项.

6.5.8 Vary

首部字段Vary可对缓存进行控制.

仅对Vary指定的首部字段的值匹配的才返回缓存, 否则必须从源服务器重新获取资源.

比如:

1
Vary: Accept-Language

如果请求的Accept-Language的值和缓存的不同, 必须从源服务器重新获取.

6.5.9 WWW-Authenticate

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

6.6 实体首部字段

6.6.1 Allow

首部字段Allow用于通知客户端能够支持Request-URI指定资源的所有HTTP方法.

6.6.2 Content-Encoding

首部字段Content-Encoding会告知客户端服务器对实体的主体部分选用的内容编码方式.

6.6.3 Content-Language

首部字段Content-Language会告知客户端, 实体主体使用的自然语言(指中文或英文等语言).

6.6.4 Content-Length

首部字段Content-Length表明了实体主体部分的大小(单位是字节). 对实体主体进行内容编码传输时, 不能再使用Content-Length首部字段.

6.6.5 Content-Location

首部字段Content-Location给出与报文主体部分对应的URI. 比如请求返回的页面内容与实际请求的对象不同时, 就会指明实际对象的URI.

6.6.6 Content-MD5

首部字段Content-MD5是一串由MD5算法生成的值, 目的在于检查报文主体在传输过程中是否保持完整. 通常这个值是对报文主体执行MD5算法获得的128位二进制数, 由于HTTP首部无法记录二进制值, 因此需要通过Base64编码处理. 但是这种方法是无法检测内容是否被恶意篡改的, 因为内容篡改后, 再重新计算篡改后的MD5再编码写进Content-MD5, 那么接收方是无法意识到内容篡改的.

6.6.7 Content-Range

针对范围请求, 返回响应时使用的首部字段Content-Range, 能告知客户端作为响应返回的实体的哪个部分符合范围请求.

6.6.8 Content-Type

首部字段Content-Type说明了实体主体内对象的媒体类型.

6.6.9 Expires

首部字段Expires会将资源失效的日期告知客户端. 但当首部字段Cache-Control有指定max-age指令时, 比起首部字段Expires, 会优先处理max-age指令.

6.6.10 Last-Modified

首部字段Last-Modified指明资源最终修改的时间.

6.7 为Cookie服务的首部字段

Cookie虽然没有被编入标准化HTTP/1.1的RFC2616中, 但在Web网站方面得到了广泛的应用.

expires属性

Cookie的expires属性指定浏览器可发送Cookie的有效期. 省略时有效期为Session级别.

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

path属性

Cookie的path属性可用于限制指定Cookie的发送范围的目标文件目录. 不过另有办法可避开这项限制, 看来对其作为安全机制的效果不能抱有期待.

domain属性

通过Cookie的domain属性指定的域名可做到与结尾匹配一致.

secure属性

Cookie的secure属性用于限制Web页面仅在HTTPS安全连接时, 才可以发送和回收Cookie.

HttpOnly属性

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

通常从Web页面内还可以对Cookie进行读取操作, 但使用JavaScript的document.cookie就无法读取附加HttpOnly属性后的Cookie的内容了.

首部字段Cookie会告知服务器, 当客户端想获得HTTP状态管理支持时, 就会在请求中包含从服务器收到的Cookie. 接收到多个Cookie时, 同样可以以多个Cookie形式发送.

6.8 其他首部字段

HTTP首部字段是可以自定扩展的. 所以在Web服务器和浏览器的应用上, 会出现各种非标准的首部字段.

6.8.1 X-Frame-Options

首部字段X-Frame-Options属于HTTP响应首部, 用于控制网站内容在其他Web网站的Frame标签内的显示问题. 其主要目的是为了防止点击劫持(clickjacking)攻击. 能在所有的Web服务器端预先设定好X-Frame-Options字段值是最理想的状态.

6.8.2 X-XSS-Protection

首部字段X-XSS-Protection属于HTTP响应首部, 它是针对跨站脚本攻击(XSS)的一种对策, 用于控制浏览器XSS防护机制的开关.

6.8.3 DNT

DNT是Do Not Track的简称, 意为拒绝个人信息被收集, 是表示拒绝被精准广告追踪的一种方法. 当然你需要服务器有相关实现才行, 商业老大哥可能才不会管你.

6.8.4 P3P

用户隐私相关.

7. 确保Web安全的HTTPS

7.1 HTTP的缺点

HTTP主要有这些不足:

  • 通信使用明文(不加密), 内容可能会被窃听
  • 不验证通信方的身份, 因此有可能遭遇伪装
  • 无法证明报文的完整性, 所以有可能已遭篡改

这些问题不仅在 HTTP 上出现, 其他未加密的协议中也会存在这类问题.

7.1.1 通信使用明文可能会被窃听

由于 HTTP 本身不具备加密的功能, 所以也无法做到对通信整体(使用 HTTP 协议通信的请求和响应的内容)进行加密. 也就是说, HTTP 报文使用明文(指未经过加密的报文)方式发送.

TCP/IP 是可能被窃听的网络

TCP/IP 协议族的工作机制, 通信内容在所有的通信线路上都有可能遭到窥视. 即使已经经过加密处理的通信, 也会被窥视到通信内容, 这点和未加密的通信是相同的. 只是说如果通信经过加密, 就有可能让人无法破解报文信息的含义, 但加密处理后的报文信息本身还是会被看到的.

加密处理防止被窃听

  1. 通信的加密

HTTP 协议中没有加密机制, 但可以通过和 SSL 或 TLS 的组合使用, 加密 HTTP 的通信内容.

与 SSL 组合使用的 HTTP 被称为 HTTPS 或 HTTP over SSL.

  1. 内容的加密

也就是把 HTTP 报文里所含的内容进行加密处理(报文首部未被加密, 报文主体被加密).

但这种方式不同于 SSL 或 TLS 将整个通信线路加密处理, 所以内容仍有被篡改的风险.

7.1.2 不验证通信方的身份就可能遭遇伪装

存在”服务器是否就是发送请求中 URI 真正指定的主机, 返回的响应是否真的返回到实际提出请求的客户端”等类似问题.

任何人都可发起请求

在 HTTP 协议通信时, 由于不存在确认通信方的处理步骤, 任何人都可以发起请求. 服务器只要接收到请求, 不管对方是谁都会返回一个响应(仅限于发送端的 IP 地址和端口号没有被 Web 服务器设定限制访问的前提下).

不管是谁发送过来的请求都会返回响应, 因此不确认通信方, 会存在以下各种隐患:

  • 无法确定请求发送至目标的 Web 服务器是否是按真实意图返回响应的那台服务器. 有可能是已伪装的 Web 服务器.
  • 无法确定响应返回到的客户端是否是按真实意图接收响应的那个客户端. 有可能是已伪装的客户端.
  • 无法确定正在通信的对方是否具备访问权限.
  • 无法判定请求是来自何方, 出自谁手.
  • 即使是无意义的请求也会照单全收. 无法阻止海量请求下的 Dos 攻击.

查明对手的证书

虽然使用 HTTP 协议无法确定通信方, 但如果使用 SSL 则可以. SSL 不仅提供加密处理, 而且还使用了一种被称为证书的手段, 可用于确定方.

7.1.3 无法证明报文完整性, 可能已遭篡改

接收到的内容可能有误

没有任何办法确认, 发出的请求 / 响应和接收到的请求 / 响应是前后相同的.

像这样, 请求或响应在传输途中, 遭攻击者拦截并篡改内容的攻击称为中间人攻击 MITM.

如何防止篡改

虽然有使用 HTTP 协议确定报文完整性的方法, 但事实上并不便捷, 可靠.

提供文件下载服务的 Web 网站也会提供相应的以 PGP 创建的数字签名及 MD5 算法生成的散列值. PGP 是用来证明创建文件的数字签名, MD5 是由单向函数生成的散列值.

不管用哪一种方法, 都需要操纵客户端的用户本人亲自检查验证下载的文件是否就是原来服务器上的文件. 浏览器无法自动帮用户检查.

可惜的是, 用这些方法也依然无法百分百保证确认结果正确. 因为 PGP 和 MD5 本身被改写的话, 用户是没有办法意识到的.

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

7.2.1 HTTP 加上加密处理和认证以及完整性保护后既是 HTTPS

7.2.2 HTTPS 是身披 SSL 外壳的 HTTP

通常, HTTP 直接和 TCP 通信. 当使用 SSL 时, 则演变成先和 SSL 通信, 再由 SSL 和 TCP 通信了.

SSL 是独立于 HTTP 的协议, 所以不光是 HTTP 协议, 其他运行在应用层的 SMTP 和 Telnet 等协议均可配合 SSL 协议使用. 可以说 SSL 是当今世界上应用最为广泛的网络安全技术.

7.2.3 相互交换密钥的公开密钥加密技术

HTTPS 采用混合加密机制

HTTPS 采用对称加密和非对称加密两者并用的混合加密机制. 非对称加密的处理速度比对称加密的处理速度要慢. 所以要充分利用两者各自的优势. 在交换密钥环节使用非对称加密, 之后的建立通信交换报文阶段则使用对称加密方式.

7.2.4 证明公开密钥正确性的证书

如何确保客户端接收的服务器公钥, 真的是那个服务器颁发的公钥? 为了解决这个问题, 可以使用由数字证书认证机构(CA, Certificate Authority)和其相关机关颁发的公开密钥证书.

  1. 服务器把自己的公钥登录至 CA .
  2. CA 用自己的私钥给服务器的公钥签名并颁发公钥证书.
  3. 服务器将服务器的公钥和 CA 的数字签名发送给客户端.
  4. 客户端已经预先存有 CA 的公钥, 因此可以验证服务器传来服务器公钥的 CA 的数字签名.
  5. 客户端使用经过验证的服务器公钥加密数据, 然后发送给服务器.
  6. 服务器用私钥解密客户端发来的数据.

可证明组织真实性的 EV SSL 证书

证书的一个作用是用来证明作为通信一方的服务器是否规范, 另外一个作用是可确认对方服务器背后运营的企业是否真实存在. 拥有该特性的证书就是 EV SSL 证书.

7.2.5 HTTPS 的安全通信机制

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

SSL 和 TLS

SSL 技术最初是由网景公司率先倡导的, 开发过 SSL3.0 之前的版本. 目前主导权已转移到 IETF 的手中.

IETF 以 SSL3.0 为基准, 后又制定了 TLS1.0, TLS1.1, TLS1.2. TSL 是以 SSL 为原型开发的协议, 有时会统一称该协议为 SSL.

SSL 速度慢吗

HTTPS 使用 SSL 时, 它的处理速度比 HTTP 慢 2 到 100 倍.

SSL 的慢主要是通信慢和加密解密运算消耗 CPU 及内存等资源的慢.

一般来说如果是非敏感信息则使用HTTP通信, 只有在包含个人信息等敏感数据时, 才利用HTTPS加密通信.

8. 确认访问用户身份的认证

8.1 何为认证

8.2 BASIC 认证

8.3 DIGEST 认证

8.4 SSL 客户端认证

8.5 基于表单认证

8.5.1 认证多半为基于表单认证

9. 基于 HTTP 的功能追加协议

9.1 基于 HTTP 的协议

9.2 消除 HTTP 瓶颈的 SPDY

9.2.1 HTTP 的瓶颈

9.2.2 SPDY 的设计与功能

9.2.3 SPDY 消除 Web 瓶颈了吗

9.3 使用浏览器进行全双工通信的 WebSocket

9.3.1 WebSocket 的设计与功能

9.3.2 WebSocket 协议

9.4 期盼已久的 HTTP/2.0

9.5 Web 服务器管理文件的 WebDAV

9.5.1 扩展 HTTP/1.1 的 WebDAV

9.5.2 WebDAV 内新增的方法及状态码

10. 构建Web内容的技术

11. Web的攻击技术

11.1.1 HTTP 不具备必要的安全功能

HTTP 不像 SSH 有协议级别的认证及会话管理等功能, 因此开发者需要自行设计并开发认证及会话管理功能来满足 Web 应用的安全.

11.1.2 在客户端即可篡改请求

11.1.3 针对 Web 应用的攻击模式

  • 主动攻击: 针对服务器
  • 被动攻击: 诱导用户, 设计陷阱

11.2 因输出值转义不完全引发的安全漏洞

11.2.1 跨站脚本攻击

11.2.2 SQL 注入攻击

11.2.3 OS 命令注入攻击

11.2.4 HTTP 首部注入攻击

11.2.5 邮件首部注入攻击

11.2.6 目录遍历攻击

11.2.7 远程文件包含漏洞

11.3 因设置或设计上的缺陷引发的安全漏洞

11.3.1 强制浏览

11.3.2 不正确的错误消息处理

11.3.3 开放重定向

11.4 因会话管理疏忽引发的安全漏洞

11.4.1 会话劫持

11.4.2 会话固定攻击

11.4.3 跨站点请求伪造

11.5 其他安全漏洞

11.5.1 密码破解

11.5.2 点击劫持

11.5.3 DoS 攻击

11.5.4 后门程序