通过实验认识HTTP代理

首先需要明确本文要介绍的HTTP代理和类似Nginx的反向代理并不相同,本文所介绍的HTTP代理是指用户主动使用的代理,而Nginx反向代理一般来说是网站管理者会主动使用,但是一个网站是否使用了反向代理对于用户来说并没有什么区别。

一般用户使用HTTP代理主要出于以下几个原因:

无法直连目标网站,使用HTTP代理做中转站,比如:科学上网,访问某些内网等优化网络体验,比如国内直连http://github.com一般很慢,有一些HTTP代理对此做了优化隐藏自己的真实IP

本文会通过几个简单的实验来说明HTTP代理的原理,实验环境是在Ubuntu下。

本文的主要内容:

简单介绍HTTP原理介绍通过HTTP代理访问HTTP网站的原理介绍通过HTTP代理访问HTTPS网站的原理

HTTP原理

讲HTTP代理之前,首先简单介绍一下HTTP的原理。

HTTP原理简单来说,就是:“用户向目标网站服务器发送一段文本,网站服务器从文本中解析出用户想要访问的内容,然后将内容返回给用户”。而这个发送与接收的过程就是基于TCP的。

首先演示一下正常访问百度的情况,这里使用curl工具,访问地址,可以看到百度向我们返回了一段文本,而这段文本通过浏览器渲染之后就是我们看到的百度首页:

curl访问百度

那么我们发送给百度的文本是怎样的呢?实际上是一个HTTP Request格式的字符串。HTTP Request格式的字符串可以非常复杂,但是最重要的只有下面两行:

GET / HTTP/1.1 Host: www.baidu.com

第一行描述了想要访问的内容,以及自己的HTTP版本。

第二行描述了访问的是哪个网站,这个可以详细说一下。 在互联网的早期,一般一个网站服务器上只会架设一个网站,因此网站服务器只需要根据第一行的内容就可以解析用户的请求,然后返回数据。 但是现在同一个服务器上可能会部署多个网站,比如同一台服务器上可能同时部署了www.baidu.com和tieba.baidu.com网站,那么只根据上面第一行的信息是无法分辨出访问的是哪个网站,因此约定用户在访问网站的时候,发送的文本中必须带上Host字段,用以明确指明访问的网站地址,网站服务器在解析的时候就不会弄错。

这里我们可以做一个实验,先准备一个文件send.txt,里面包含如下内容:

GET / HTTP/1.1 Host: www.baidu.com User-Agent: curl/7.58.0

注:send.txt一共有4行,也就是说在User-Agent下面还有一个空白行。缺少空白行将导致网站服务器无法正常解析。

实际上去掉User-Agent那一行之后,实验也能进行,但是访问百度服务器返回内容是带有大量广告的首页,不便于展示。

我们使用命令ping www.baidu.com可以看到百度服务器的IP地址,然后我们使用nc命令将send.txt中的内容发送出去,就可以看到百度服务器返回给我们的结果了。

整个流程如下:

自己构造HTTP Requestnc命令全称是netcat,可以非常方便的建立TCP连接,nc命令的第一个参数是TCP连接的IP地址,第二个参数是TCP连接的端口号。HTTP协议的默认端口号是80。 使用ping命令可以查询到www.baidu.com的IP地址,不同地区甚至不同时间运行这个命令可能会的到不同的结果,这是正常的。读者使用自己运行ping命令返回的IP地址即可重现本实验。

可以看到,相比于直接使用curl命令获取到的数据,nc命令返回的数据多了一些内容:

HTTP/1.1 200 OK Accept-Ranges: bytes ...

这部分就是HTTP Response的头部信息,其中第一行表示我们的请求被正确处理了。HTTP Response头部数据通常记录了本次返回数据的格式长度等信息,Cookie等内容也是在这个区域中。

以<!DOCTYPE html>开头的内容就是浏览器将会渲染的内容,从这部分开始就和curl命令返回的结果完全相同了。

总结一下,一个HTTP请求的整个流程可以用下如表示:

HTTP请求流程图

用户首先根据自己想要访问的内容准备好一段文本,并将这段文本发送给网站服务器。网站服务器对文本进行解析之后,将数据再发送给用户。这样就完成了一个HTTP请求。

如何使用HTTP代理访问HTTP网站?

HTTP代理应该是所有代理中最简单的一类代理,它的工作原理非常简单,就是用户将原本打算发送给网站服务器的文本原封不动地发送给代理服务器,代理服务器再将这个文本转发给网站服务器并接收网站服务器的返回的数据,再由代理服务器转发给用户。

在这个过程中,对于用户来说代理服务器扮演了和网站服务器完全相同的角色,因此对于用户来说使用HTTP代理是非常简单的一件事情。

而代理服务器所做的工作则是进行必要的数据转发,最大的难点在于从用户发来的请求当中识别出网站服务器地址和维护TCP连接,具体代理服务器的实现方法超出了本文所讨论的内容,之后有机会再做分享。

接下来依然通过实验来说明。

首先我们需要在电脑上搭建一个HTTP代理服务器,在Ubuntu系统下可以直接使用tinyproxy,运行以下命令即可:

sudo apt install tinyproxy

上面这个命令会自动在电脑上搭建一个HTTP代理服务器,默认的端口号是8888,并且默认只允许本机使用代理,如果想要在其他电脑使用这个代理,需要修改/etc/tinyproxy/tinyproxy.conf文件。

我们将之前准备的send.txt文件发送给tinyproxy,如下:

通过代理访问HTTP网站

可以看到通过代理服务器,我们也成功收到了百度返回的数据,同时注意到返回的数据中多了一行Via: 1.1 tinyproxy (tinyproxy/1.8.4),这一行就是tinyproxy自己添加的,在实际使用中完全可以忽略。

通过代理服务器,整个流程如下:

通过代理访问HTTP网站的流程图

如何使用HTTP代理访问HTTPS网站?

我们在访问HTTPS网站的时候,第一步并不是准备好请求的文本,而是先与网站服务器进行HTTPS握手。这个握手过程必须有HTTPS网站服务器的私钥参与,而代理服务器并不拥有这个私钥,因此这个握手无法由代理服务器代为建立。

在通过代理服务器访问HTTPS网站的过程中,代理服务器所扮演的角色仅仅是转发TCP数据(在访问HTTP网站的时候,代理服务器转发的是HTTP数据)。

在使用代理服务器的情况下,一个完整HTTPS请求要经历如下几个步骤:

首先用户向代理服务器发起CONNECT请求代理服务器解析CONNECT请求,向网站服务器建立TCP连接,但是并不发送任何数据代理服务器向用户返回数据,表示TCP连接已经建立了,此后代理服务器就只负责数据的转发,代理服务器看到的数据是加密之后的,无法查看原始数据或者对数据进行修改然后用户和网站服务器建立HTTPS握手之后用户和网站服务器之间的流程与一般的HTTP请求流程完全相同

用图片来描述的话如下:

使用代理访问HTTPS网站的流程图

我们可以做个实验来验证代理服务器的CONNECT阶段。

首先准备一个connect.txt文件,里面的内容是:

CONNECT www.baidu.com:443 HTTP/1.1 Host: www.baidu.com:443

依然要注意文件的最后有一个空白行。

然后使用nc命令将这些内容发送给tinyproxy:

CONNECT阶段

可以看到,tinyproxy在和百度建立了TCP连接之后,向我们返回了Connection established信息,这表示我们可以进行HTTPS握手了。

总结

至此,我们已经完全弄清楚了HTTP代理的原理。如果你有任何疑问,或者是对实验存在不同的理解,欢迎通过评论区和我讨论。