技术分享| HTTP 代理

一、序

在 HTTP 协议中,最基础的就是请求和响应的报文,而报文又由报文头和报文实体组成。大多数 HTTP 协议的使用场景,都是依赖设置不同的 HTTP 请求/响应 的 Header 来实现的。

既然要说到代理,先提两个问题来当主线,从问题出发讲解 HTTP 代理。

  1. 抓包工具是如何实现 HTTP 抓包的。
  2. 对于 HTTPS 流量,不安装证书的情况下,通过抓包工具,请求和响应依然正常。

今天说的 HTTP 代理,更多的是一种抽象概念,其中的原理才是最关键的。

二、HTTP 代理

2.1 什么 HTTP 代理?

说到 HTTP 代理,作为客户端开发,最熟悉的就是使用 Fiddler、Charles 等工具进行抓包时,需要在手机上挂个代理,来方便我们排查一些网络问题,这只是代理众多使用场景中的一个。

实际上,HTTP 代理(Web 代理)是一种存在于网络中间的实体,可以提供各种功能。 如果没有 HTTP 代理,客户终端就要直接与终端服务器进行交互。而有了 HTTP 代理后,客户终端就可以与代理通信,然后由代理代表客户端与服务器进行交互。

HTTP 代理算是最容易理解的一个 HTTP 协议概念,它和我们的生活最贴近。在我们的生活中,存在各种代办的服务。

例如你和女友准备出国游,一些不免签的国家,就需要提前办理签证。我们不熟悉自然觉得流程很复杂,这时就可以选择交由旅行社来代理办理签证,你只需要根据对方提供的清单准备材料,就可以很方便的获得签证。在这个过程中,你节省了时间,而旅行社赚了你一点钱。

在这里插入图片描述

代理服务,就是代理客户端完成事务处理的中间人,它接管客户端的事务,代替客户端与服务端交互。

代理服务是一个抽象的中间实体,可以存在网络的各个中间点,浏览器、路由器、代理服务器、Web 服务器的反向代理等,

2.2 HTTP 代理的分类

从最熟悉的抓包工具说起,Fiddler、Charles 这种抓包工具,封装的都非常好,哪怕我们完全不理解 HTTP 代理的细节,简单配置就可以使用。

在使用过程中,你会发现两种场景:

  1. 对于 HTTP 协议请求,可以直接显示请求/响应报文的细节
  2. 对于 HTTPS ,如果没有导入证书,请求依然可以发送至服务器,并且也可以正常返回数据,但是不会显示报文细节。

在没有导入证书的情况下,HTTPS 请求我们无法获知细节,但是并不影响我们的请求和响应。

这个两种不同的表现,也对应了两种不同的 HTTP 代理:

  1. 普通代理。基于修订后的 RFC 2616 在 HTTP/1.1 中被定义。这种代理扮演的是「中间人」的角色。对客户端来说,它是服务端,而对真正的服务端来说,它又是客户端,它就是负责在两端之间传递 HTTP 报文。
  2. 隧道代理。这种一种基于 TCP 协议的隧道传输代理,它通过 HTTP 协议的 CONNECT 方法完成通信,以 HTTP 的方式,实现任意基于 TCP 的应用层协议代理。

接下来我们就分别对这两种代理进行讲解。

2.3 普通代理

普通代理,理解起来并不复杂,它是网络中的中间实体,位于客户端和服务端之间,扮演「中间人」的角色,在两端之间来回传递报文。

这个「中间人」左手牵着客户端,右手牵着服务端,在收到客户端发送的请求报文时,需要正确的处理请求和连接状态,同时向服务器发送新的请求,在收到响应后,将响应结果包装成一个响应体返回给客户端。

在这里插入图片描述

在普通代理的流程中,代理两端都是有可能察觉不到「中间人」的存在。

举个例子,我们要访问 A 网站,实际上我们是向代理服务器发送请求,而代理服务器又再向 A 网站发起请求,最终将响应体通过代理服务器,返回给我们。在我们的角度,我们正常的向一个网站服务器发起请求,并且对方也返回给我们正确的数据,在这个过程中,我作为客户端,会认为代理服务器就是 A 网站的服务器,而 A 网站的服务器,又认为代理服务器是一个真实的用户。

这里说到,代理服务器作为「中间人」是可以隐藏自己的存在,但是如果我们作为一个“守规矩”的代理服务器,想要将客户端的 IP 传递给服务端,可以通过 X-Forwarded-IP 这个自定义的 Header,来告诉服务端真正的客户端 IP 地址。

HTTP 协议作为一种松散的协议,服务器在接收到 X-Forwarded-IP 这个请求头时,是无法验证其真伪的。它可能是代理服务器伪造的,也可能是真实的。所以服务端从 HTTP 头部获取 IP 时,就需要格外小心。

普通代理很好理解,但是它也有缺陷,它只适用于 HTTP 协议。

在普通代理模式下,所有请求响应的数据,对于代理这个「中间人」来说,都是透明并且可以任意操作,这就会带来各种数据安全的隐患。

说到网络数据安全,首先想到的就是 HTTPS,但是 HTTPS 这种证书认证的机制,又是中间人劫持的克星。

严格上来说,HTTPS 下不存在中间人攻击,除非是人为的犯错了,没有对证书严格校验,或者证书被泄露。

在普通的 HTTPS 请求中,服务端不验证客户端的证书,中间人可以作为客户端与服务端完成 TLS 握手。

但是由于代理中间人没有证书密钥,也就无法伪造服务端和客户端简历的 TLS 连接,这会导致请求失败。

这个场景,对标到抓包工具的工作流程中,你会发现,如果想用 Charles(或Fiddler) 抓 HTTPS 的网络数据包,就需要在手机上安装一个 Charles 的 CA 证书,让手机设备信任此证书,才可以完成抓包,此时走的就是普通代理的模式。

那换个角度,假如在手机上没有安装 Charles 提供的证书,也并没有影响到请求和响应,Charles 只是无法解密 HTTPS 数据,这是如何做到的呢?

这就需要用到隧道代理。

2.4 隧道代理

隧道代理,又称为 Web 隧道(Web tunnel),这种方式可以通过 HTTP 连接发送非 HTTP 流量,这样可以在 HTTP 上捎带其他协议的数据。

隧道代理是利用 HTTP 的 CONNECT 方法建立起来的。CONNECT 方法,最初并不是 HTTP/1.1 的核心规范,但却是一种得到广泛使用的扩展,它在 2014 年发布的 HTTP/1.1 修订版中,才对 CONNECT 及隧道代理有了清晰的描述。

HTTP 隧道代理的工作流程是什么样的?

一次普通的 HTTP 请求,Header 部分以连续的两组 CRLF(\r\n)作为结束标记,如果后面还有内容,就是 Content 部分的内容,也称为请求/响应体(Content),如果存在 Content 内容,就需要在 Header 中增加 Content-Length 来标记 Content 部分的长度。接收方(服务端)会根据这个长度来读取数据。

CONNECT 报文的请求,是没有 Content 部分的,只有 Request-Line 和 Header,他们仅供代理服务器使用,并不会传递给终端服务器。请求的 Header 部分一旦结束(两组连续的 CRLF),后面的所有数据,都被视为应该转发给终端服务器的数据,代理需要把他们无脑的直接转发,并且不限制长度,直到从客户端的 TCP 读通道关闭。

CONNECT 的响应报文,在代理服务器和终端服务器建立连接后,可以向客户端返回一个 200 Connect established 的状态码,以此表示和终端服务器的连接,建立成功。这个 200 Connect established 的 Header 部分一旦结束(两组连续的 CRLF),后面所有的数据均为远端服务器返回的数据,同理,代理服务器会直接转发终端服务器的数据给客户端,直到终端服务器的 TCP 读通道关闭。

在这里插入图片描述

了解清楚 HTTP 隧道的工作流程之后,就知道 CONNECT 方法请求隧道网管创建一条到达任意目的服务器和端口的 TCP 连接,并对客户端和服务端之间的后续数据,进行无脑的盲转发。

通过隧道代理,代理服务器不再作为中间人,不再需要改写浏览器的请求,而是把浏览器和终端服务器的数据,原样转发,这样浏览器就可以直接和终端服务器进行 TLS 握手,并传输加密的数据。

2.5 导入证书后,Charles 抓 HTTPS 流程

Charles 作为抓包工具,在手机上没有导入证书的时候,是通过隧道代理来保证数据的传输。一旦导入证书之后,Charles 就又切换到普通代理的工作模式,此时我们就可以解析 HTTPS 的流量数据。

这里简单说一下原理。

在导入证书后,请求时手机就会信任 Charles 伪造的证书,而 Charles 又伪装成真实的客户端与服务端之间建立正确的 TLS 连接。此时,Charles 作为「中间人」,两端的 TLS 流量都是可以被解密的。

三、总结时刻

到这里就了解清楚 HTTP 代理的细节,其实很抽象的概念,也很好理解。

简单来说,HTTP 代理可以分为两类,普通代理和隧道代理。

普通代理作为「中间人」存在,在一次请求中,客户端明文请求代理服务器,在收到请求后,代理服务器又明文去请求终端服务器。在这整个过程中,数据都是明文传输,中间人可以对其中传递的数据进行改写,这就是著名的中间人攻击,可见其有多不安全。

这就引申出了支持 HTTPS 的隧道代理,此时代理服务器就不再作为中间人,无法改写客户端的请求,而仅仅是在建立连接后,将客户端的请求,通过建立好的隧道,无脑的转发给终端服务器。

在这里插入图片描述

posted @ 2022-07-15 10:30  anyRTC  阅读(630)  评论(0编辑  收藏  举报