Http权威指南笔记(六)——代理

上一篇学习了Web服务器,这一篇我来学习一下代理的知识。现在的网络中存在着各种各样的代理。学习Web代理服务器,更有利于我们队网络请求过程的理解。

简介

代理服务器是网络的中间实体,其既是Web服务器,也是Web客户端。所以其必须要能正确处理客户端的请求,并返回响应,同时也要能正确的向服务器发起请求并接收响应。

1.1 私有和共享代理

代理服务器可以作为某个客户端单独使用的私有代理,也可以作为众多客户端共有的代理服务器——即公共代理。
实际当中,公共代理更为常见,它是一种集中式代理。比如缓存代理,我们可以将某一个区域的缓存放入一个代理服务器中,那这个区域任何客户端都能利用同一个缓存代理
私有代理,相对来比较少见,一般都是用户自行有某些特殊需求的时候,专门为客户端配置代理服务器。

1.2 代理与网关

代理与网关都是网络中的中间实体,虽然看起来作用相似。但是他们有一点区别就是:代理连接的一般是用的同一种协议应用程序。而网关一般是用于连接不同协议的应用程序。如下图就展示了代理与网关的区别:
代理与网关
上图a中,Web代理与客户端和服务器之间的传输协议都是用的HTTP协议。图b的网关,与客户端使用的是HTTP协议,与服务器端则采用的是POP协议。其作用是让客户可以在浏览器上用HTTP协议进行收发邮件了。

2 代理的用途

客户端和服务器端直接通信相较于通过代理的时间,理论上来说应该更短,为什么还需要在中间加一个代理呢?这就不得不说代理的用途,或者说给我们带来的好处。

  • 内容过滤器
    通过代理,我们可以对网络上的资源进行过滤,某些不合适客户端的资源,我们可以将其过滤掉。比如对于小孩而言,我们可以通过代理将网络上的成人内容进行过滤,或者对于在校学生而言,我们可以过滤掉那些和学习无关的内容,让学生专注于学习的内容。
  • 访问权限控制
    这种用途在一些企业的里面非常常见,通过对访问控制的策略进行配置,达到控制员工的越级访问。比如:销售部的员工,不应该查询公司保密财务资料和,这个时候我们可以通过代理,对发起请求的用户进行判断,如果需要访问保密财务数据,就需要密码之类的指令,否则阻止其对越级资源的访问,如下图所示:
    访问权限控制
  • 安全防火墙
    网络安全工程师通常会使用代理服务器来提高安全性。代理服务器会在网络中的单一安全节点上限制哪些应用层协议的数据可以流入或流出一个组织。还可以提供用来消除病毒的 Web 和 E-mail 代理使用的那种挂钩程序
  • Web缓存
    根据需要,我们可以在代理服务器上缓存某些资源的副本,客户端在获取资源的时候,就能够直接在代理服务器中获取,而无需连接最终目的Web服务器,既可以减少Web服务器的并发量,也能节约带宽资源。
  • 反向代理
    代理可以假扮Web服务器与客户端进行通信,这种代理通常被称为反向代理。他们代理服务器来接收客户端的真实请求,然后根据需要,将请求定位到所需要的服务器资源。这种代理可以提高访问慢速Web服务器时候的性能(即一个加速器的作用),同时也可以达到负载均衡的目的。当一个请求来到的时候,可以根据当前所有服务器的负载情况,将请求给负载相对较低的服务器进行处理。
  • 内容路由器
    对这一用途不是非常理解,目前理解就是可以将用户分级,如:普通,付费,VIP等。然后根据不同的用户,提供不同的内容,示例图如下:
    内容路由器
  • 转码器
    代理服务器在将内容发送给客户端之前,可以修改内容的主体格式。在这些数据表示法之间进行的透明转换被称为转码(transcoding)。如:传输图片或者文档的时候,可以先对其进行压缩,然后再进行传输。
  • 匿名代理
    匿名代理的主要目的在于保护隐私,它会主动的从HTTP报文中书删除一些和用户身份信息相关的东西,如客户端 IP 地址、From 首部、Referer 首部、cookie、URI 的会话 ID。

3 代理的层次及结构

3.1 代理的部署位置

根据代理的目的不同,可以将代理部署在不同的地方,常见的如下图所示:
代理的位置
图a中的代理,部署在LAN的出口处的局部私有代理,由其统一代理和管理本地客户端发起的请求。这样可以就本地客户端发起请求进行管理。如:很多企业会使用该种方式,管理员工日常工作中的网络访问,一些不允许访问的地址就会被拦截和过滤。
图b中的代理,一般被称为访问代理,这种代理在IPS提供商会经常用到,可以集中处理客户端的请求,同时可以作为缓存代理,将一些经常使用的资源进行缓存,让用户可以高速访问资源,同时节约带宽资源。
图c中的就是常说的反向代理,这个前面已经介绍过了,这里不摘赘述。
图d一般被称为网络交换器,放在真正的英特网交换节点中间,也是可以通过缓存来实现减少英特网节点之间的拥堵,同时也能实现对流量进行监控。

3.2 代理的层次结构

所谓的代理层级结构,即代理相互之间的关系。在关系当中涉及到父代理和子代理两个概念。这两个概念是同时成对出现,是一种相对的概念。父代理是指更靠近服务器端的代理,相对的子代理即更靠近客户端的代理。以下图为例:
代理层次结构
代理2为代理1的父代理,代理3位代理2的父代理,代理2称为代理3的子代理,代理1称为代理2的子代理。
在实际当中,一般代理的层次结构并非是禁止不变的,根据请求的不同,可能代理会选择将请求转发给不同的下级代理,甚至直接转发给原始Web服务器。实际当中,常见的动态代理情景有如下几个:

  • 负载均衡——代理会根据当前它的下一级代理的负载情况,来决定将当前请求转发给哪个父代理,以便达到负载均衡的目的。
  • 地理位置附件路由——代理会根据当前地理位置和请求的情况,选择不同地方的父代理。
  • 协议/类型路由——根据商定的协议或者URI来决定将当前请求转发到哪个父代理上。
  • 基于订购的路由——也就是常见的如果是付费用户,就将转发到高速缓存服务器,如果是普通用户,就转发到一般的Web服务器。这样就能提高付费用户的体验性能。

3.3 如何将请求流行代理

  • 修改客户端配置——可以直接修改客户端(如浏览器)的配置,让其请求发送到我们制定的代理上。
  • 修改网络——这种一般是网络服务提供商进行的操作,这些服务商对网络交换和路由设备进行监视,再需要的时候,对请求进行拦截转发。一般对用户而言是透明的。用户感知不到请求被发送到代理了。
  • 修改DNS命名空间——通过对DNS的命名空间进行修改,让代理假扮服务器的角色。这样客户端发送给Web服务器的请求就会被发送到代理。如日常使用的反向代理,客户端正常发送的请求会先被发送到方向代理,然后再由其真正给到Web服务器。
  • Web服务器的配置——通过对Web服务器进行修改和配置,将一些请求通过重定向的方式转发到代理服务器上。

4 追踪报文

现在将请求从客户端发送到服务端的路径上通过多个代理的转发是很常见的。有时候当出现问题的时候,我们需要跟踪整个请求路径上报文的转发流程,本节就是介绍怎么去跟踪代理转发的报文。

4.1 Via首部

HTTP规范指定了如果有Via首部,报文每经过一个节点,都需要将该节点添加到Via列表的末尾。通过Via首部,我们可以记录报文转发,诊断报文的循环等问题。

  1. Via的语法
    每个 Via 路标中最多包含 4 个组件:一个可选的协议名(默认为 HTTP)、一个必选的协议版本、一个必选的节点名和一个可选的描述性注释。其语法格式如下:
Via               = "Via" ":" 1#( waypoint )
waypoint          = ( received-protocol received-by [ comment ] )
received-protocol = [ protocol-name "/" ] protocol-version
received-by       = ( host [ ":" port ] ) | pseudonym

其中:
协议名:默认为HTTP,如果是HTTP可以省略,如果不是,则必须加上
协议版本:这个字段的格式和协议有关,如HTTP协议的就是 1.0,1.1等
节点名:主机名加端口号。端口号如果省略,则人为是该协议的默认端口号,主机名不一定是真实的。
节点注释:用于对节点的注释说明,可以省略。
如下面的Via首部:
Via = 1.1 cache.joes-hardware.com, 1.1 proxy.irenes-isp.net
说明有两个代理,第一个代理是 HTTP协议的1.1版本,节点为cache.joes-hardware.com,第二个代理也是HTTP协议的1.1版本,节点名称为proxy.irenes-isp.net

  1. Via的请求和响应路径
    请求和响应报文都会经过代理进行传输,因此,请求和响应报文中都要有 Via 首部。
    请求和响应通常都是通过同一条 TCP 连接传送的,所以响应报文会沿着与请求报文相同的路径回传。如果一条请求报文经过了代理 A、B 和 C,相应的响应报文就会通过代理 C、B、A 进行传输。因此,响应的 Via 首部基本上总是与请求的 Via 首部相反
  2. Via与网关
    有些代理会为使用非 HTTP 协议的服务器提供网关的功能。Via 首部记录了这些协议转换,这样,HTTP 应用程序就会了解代理链上各点的协议处理能力以及所做的协议转换了
  3. Server与Via首部
    Server首部是用于对原始服务器的描述,如:
Server: Apache/1.3.14 (Unix) PHP/4.0.4
Server: Netscape-Enterprise/4.1
Server: Microsoft-IIS/5.0

Server首部不能用于代理,代理不应该对该首部首部进行修改,代理只需要添加Via即可。

  1. Via和隐私、安全问题
    如果出于隐私或者安全考虑,不想提供主机名和端口号等信息。可以使用一个假的节点信息,但是必须要有节点信息。同时如果是同一组织下的同一协议,且同一版本,可以将多个节点合并为一个节点。但是前提是同一组织,同一协议,同一协议版本。任何一个不同都不能进行合并。

4.2 TRACE方法

通过 HTTP/1.1 的 TRACE 方法,用户可以跟踪经代理链传输的请求报文,观察报文经过了哪些代理,以及每个代理是如何对请求报文进行修改的。TRACE 对代理流的调试非常有用。当然,前提是要服务器支持TRACE方法。
如下所示,展示了TRACE方法请求响应过程:
TRACE方法
从图中可以看到,TRACE的处理过程为:当TRACE请求到达服务器后,如果服务器支持该方法,会将完整的请求报文封装为响应体,然后返回给客户端。响应头中的Content-type的值为:message/http。客户端收到该响应后,就能通过响应体中的数据知道请求报文最终被修改后的内容。
一般情况下,TRACE的请求会沿着整条路径一路转发,最终达到原始服务器。但是如果请求体中包含Max-forward,那转发次数就会被限制在该首部规定的值以内。工作原理是,没经过一次转发,就会将Max-forward的值-1,当其值为0的时候,就证明达到了最大限制,这个时候无论是否达到最终服务器,都应该结束该条请求继续转发,并返回响应。

5 代理认证

代理可以作为访问控制设备使用。HTTP 定义了一种名为代理认证(proxy authentication)的机制,这种机制可以阻止对内容的请求,直到用户向代理提供了有效的访问权限证书为止。
其工作流程如下:

  1. 当一个受限访问的请求达到代理时,代理检查该访问是否有权限,如果没有,会返回一个407状态码和Proxy Authorization Required的信息,告知客户端需要使用证书。同时可以包含一个怎么获取该证书的描述信息。
  2. 客户端收到该响应后,会根据提示尝试获取证书,或者提示用户提供证书
  3. 客户端获得证书后,会再次发送请求,这次会在请求头中添加Proxy-Authorization字段来提供证书
  4. 服务器收到请求,会判断证书是否有效,有效则继续后面的流程,否则回到1的情况。

6 代理的互操作性

由于客户端,代理、服务器都是由不同的厂商进行提供。那就意味着它们之间或多或少存在一些差异。某些首部字段,可能代理支持,但是服务器不支持,又或者一些请求方法,服务器支持,代理不支持。为了更好的系统工作,一般采用如下的原则进行处理。

  1. 当代理遇到自己不能处理的首部字段的时候,一般应该将其进行转发,并且保持原有的顺序,同样,如果代理对某个方法无法处理,其应该尝试将报文转发到下一级节点。
  2. 通过OPTIONS方法,用于判断服务器所支持的特性,这样在请求前知道了服务器所支持的特性,就能更好的同不同代理和服务器之间进行互操作了
    OPTIONS请求的URI如果是一个”*“号,请求的就是整个服务器所支持的功能,如果请求的URI是某个具体的资源,就是查询指定资源支持的功能。如果OPTIONS请求成功,会返回一个200 OK的响应。其有一个Allow首部字段,其值会列出所有支持的请求方法。如:
    Allow: GET, HEAD, PUT

7 代理的一些其他问题

7.1 代理的URI和服务器URI的区别

客户端向代理和服务器发送请求的时候,URI是有区别的。如果是向服务器发送请求,URI一般不会包含shceme,host和port,如:

GET /index.html HTTP/1.0
User-Agent: SuperBrowser v1.3

如果是向代理发起请求,就会包含完整的URI路径,如:

GET http://www.marys-antiques.com/index.html HTTP/1.0
User-Agent: SuperBrowser v1.3

之所以出现上述的区别,是因为,最初没有代理的时候,客户端发送的请求都是给最终服务器的,服务器是知道自己的主机名和端口等信息的,所以为了减少冗余信息,发送部分URI就可以了。但是代理出现以后,代理可能并不是针对某单个服务器的,这个时候吗,如果没有完整的URI路径,代理就无法知道将该请求发往哪个下一级节点。
但是我们客户端并不一定都显式的知道请求是发文代理还是服务器的,这个时候采用如下原则:

  1. 没有显示设置代理的客户端,会发送部分URI;
  2. 明确设置了代理,或者客户端明确知道自己将要发送给代理的时候,发送完整的URI

到这里还需要提到的一点是,上述提到的问题,即除了URI中的路径部分外,还需要确定主机名。除了代理会遇到这个问题,前面章节提到的虚拟Web服务器也会遇到相同的问题,但是解决方式是不同,代理同时是要求直接使用完整的URI,Web虚拟主机是需要Host请求头来提供主机和端口信息。

7.2 拦截代理的URI处理

上一小节提到了,客户端在知道是发送给代理的时候,是发送完整的URI,但是像一些拦截作用的代理,客户端一般是不知道请求是发给代理的,这个时候,客户端默认只会发送部分URI。这个时候,拦截代理怎么处理请求呢?这个时候就要求我们的代理要具有处理部分URI的能力。一般代理的处理原则如下:

  • 如果提供了完的URI,则使用完整的URI
  • 如果提供了部分URI,但是有Host请求头,应该使用Host的值来确定主机名和端口信息
  • 如果提供了部分URI,且没有Host请求头,按照下面的方式处理:如果代理是反向代理一类的代理,可以用真实服务器的地址和端口号来配置代理;如果是拦截代理一类的代理,一般拦截者本身是可以提供真实主机地址和端口信息的
  • 如果代理最终都无法获得真实的主机地址和端口号等必要信息,就必须返回一条错误报文给客户端,让其提供Host请求头

最后除了上述提到的问题外,另外一个代理还需要注意的问题是,对URI的修改问题。有时候可能客户端提供的URI并不一定非常规范,这个时候代理检查到问题后,需要做的是能够识别出URI,就进行转发或者处理该请求,不行就返回错误信息,不要尝试去修正URI。虽然修正URI出发点是好的,但是可能会造成一些其他问题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章