HTTP代理服务器搭建实验

HTTP代理服务器实验

(此实验是CUC网络安全课程中的实验,将其记录在此)

实验目的

  • 掌握在linux上正确搭建HTTP正向代理的方法

实验环境

  • Ubuntu 22.04.5 LTS (Jammy Jellyfish)(代理服务器)
  • MacOS(客户端)

实验要求

  • 在代理服务器上搭建一个HTTP正向代理服务器,并使用客户端访问代理服务器,验证代理服务器是否正常工作。
  • 在代理服务器上抓包,分析使用HTTP代理服务器的通信过程。

实验步骤

查看客户端和代理服务器是否可以连通

# 在准备做代理的服务器上监听4444端口
nc -lvnp 4444

# 在客户端中curl准备做代理的服务器的4444端口
curl {准备做代理的服务器IP}:4444

然后在准备做代理的服务器上发现有客户端的请求,内容如下:

Listening on 0.0.0.0 4444
Connection received on {客户端IP} {客户端端口}
GET / HTTP/1.1
Host: {准备做代理的服务器IP}:4444
User-Agent: curl/8.15.0
Accept: */*

这一步可以获得客户端能连接到代理服务器的对应出口IP,方便后续暴露面最小的配置正向代理的服务(只代理来自客户端网段的IP地址,其他IP地址不代理,注:实验环境中客户端出口IP地址不会发生改变,若是配置互联网代理,在不同网络环境地域下访问时,客户端出口IP地址可能会发生改变,为了安全需要做其他配置)

在ubuntu上使用tinyproxy搭建HTTP正向代理服务器

基础软件安装:

sudo apt update
sudo apt install -y tinyproxy

配置文件编辑:

sudo vim /etc/tinyproxy/tinyproxy.conf

因为之前获得了客户端的出口IP,所以取消对应网段下Allow的行首注释。示例如:我之前获得了出口IP是10.190.0.38,此处我要取消Allow 10.0.0.0/8行首注释,因为10.190.0.3810.0.0.0/8网段下的其中之一的IP地址。

参数解释:

  • Allow:允许代理的IP地址段或IP,不写就是允许所有主机访问
  • Port:代理服务器的端口,不更改就是默认8888端口

配置完成后,重启tinyproxy服务:

sudo systemctl restart tinyproxy

在客户端中使用代理服务器,验证代理服务是否正常

我在客户端的浏览器中安装了一个代理切换工具,Zero Omega,可以方便的切换代理服务器,在这里的配置过程如下:

新建情景模式->代理服务器->填代理服务器名称->修改代理协议为HTTP->修改代理服务器IP和端口为我们代理服务器对应的设置->应用选项

然后使用该代理访问baidu.com,发现可以正常访问,说明代理服务器正常工作。

发现访问的已经是https站点了

在代理服务器中抓8888端口的包

此处使用tshark抓包,所以需要安装tshark

sudo apt install -y tshark

然后使用tshark抓包,监听8888端口。

sudo tshark -i any -w tinyproxy_traffic.pcap -f "port 8888"

将服务器上抓到的包scp到本地后用wireshark打开进行分析

http.request.method eq CONNECT查看所有HTTPS代理请求

随便看了一个tcp流,将图片发给ai后让它帮我分析了一下这个流的全过程:

首先,明确图中的角色:
* **客户端 (Client)**: `192.168.33.167`
* **代理服务器 (Proxy Server)**: `10.190.0.38` (这是你抓包的地方)
* **目标服务器 (Destination Server)**: `www.baidu.com` (图中未直接显示其 IP 地址,但通过 `CONNECT` 请求和 `Client Hello` 中的 SNI 可知)

整个过程可以分为以下几个关键步骤:

### 步骤 1: 建立与代理服务器的 TCP 连接 (数据包 77, 78, 88)

* **No. 77, 78, 88**: 这是一个标准的 TCP 三次握手过程。
* `SYN`: 客户端 `192.168.33.167` 向代理服务器 `10.190.0.38` 的 `8888` 端口发起连接请求。
* `SYN, ACK`: 代理服务器响应并确认请求。
* `ACK`: 客户端最终确认,连接建立。
* **分析**: 此时,客户端和代理服务器之间建立了一条普通的 TCP 连接。这条连接本身是**不加密的**。

### 步骤 2: 请求建立隧道 (数据包 93)

* **No. 93**: 这是整个过程的**核心**。客户端向代理服务器发送了一个 **HTTP `CONNECT`** 请求。
* `CONNECT www.baidu.com:443 HTTP/1.1`
* **分析**:
* 这个 `CONNECT` 方法告诉代理服务器:“请不要为我获取任何网页,我不想访问你。我只想让你帮我打通一个到 `www.baidu.com` 的 `443` 端口的 TCP 通道,然后你就在中间原样转发数据即可。”
* **非常重要的一点是**:代理服务器在这一步可以看到客户端想要访问的目标域名 (`www.baidu.com`) 和端口 (`443`)。这个 `CONNECT` 请求本身是**明文的 HTTP**。

### 步骤 3: 隧道建立成功 (数据包 106)

* **No. 106**: 代理服务器成功连接到 `www.baidu.com:443` 后,向客户端返回一个 HTTP 响应。
* `HTTP/1.0 200 Connection established`
* **分析**: 这个响应告诉客户端:“好的,我已经为你和 `www.baidu.com:443` 之间建立了通道。现在开始,你们可以自由通信了,我只负责当一个‘传话筒’。”
* 至此,一个透明的、端到端的数据管道(隧道)就在 **客户端** 和 **目标服务器 (Baidu)** 之间建立起来了,而代理服务器就在这个管道的中间。

### 步骤 4: 端到端的 TLS 握手 (数据包 113, 114, 131 等)

* 隧道建立后,客户端现在开始直接与百度的服务器进行通信,就好像代理不存在一样。
* **No. 113**: 客户端发送 `Client Hello`。这是 TLS 握手的开始。这个包被发送到代理,代理再原封不动地转发给百度服务器。
* **No. 114**: 百度服务器响应 `Server Hello`, `Change Cipher Spec` 等。这些信息通过代理原封不动地转发回客户端。
* **No. 131**: 客户端继续 TLS 握手的后续步骤。
* **分析**:
* 整个 TLS 握手过程是在**客户端和百度服务器之间**直接进行的。
* 代理服务器**无法看到**这些 TLS 握手包的内部内容(如协商的密钥等),因为它只在转发加密的字节流。对代理来说,这些都只是无意义的数据。

### 步骤 5: 传输加密的应用数据 (数据包 1051, 1055 等)

* **No. 1051, 1055**: TLS 握手成功后,双方开始传输加密的应用数据。
* `Application Data` 就是加密后的 HTTP 请求和响应(例如 `GET /index.html` 请求和返回的网页内容)。
* **分析**:
* 包 `1051` (175字节) 很可能是客户端发出的、经过 TLS 加密后的 HTTP `GET` 请求。
* 包 `1055` (2116字节) 是百度服务器返回的、经过 TLS 加密后的 HTTP 响应的开始部分。
* 代理服务器**完全无法解密或读取**这些 `Application Data` 的内容。它只知道在转发一些加密数据。

#### 步骤 5: 连接终止 (数据包 1864 - 1903) -- **【新增分析】**
* 这是数据传输完毕后,关闭连接的过程。这里采用的是 TCP 的**四次挥手**来优雅地断开连接。
* **No. 1864**: **第一次挥手**。代理服务器 `10.190.0.38` 向客户端 `192.168.33.167` 发送了一个带有 `[FIN, ACK]` 标志的包。
* `FIN` (Finish) 标志表示:“我(代理)这边的数据已经全部发送完了,我准备关闭连接了。”
* `ACK` 是为了确认之前收到的数据。
* **分析**: 代理之所以主动发起关闭,很可能是因为它与百度服务器之间的连接先被百度那边关闭了。于是代理将这个“关闭信号”传递给客户端。

* **No. 1899**: **第二次和第三次挥手**。客户端 `192.168.33.167` 回复代理服务器。
* 这个包也带有 `[FIN, ACK]` 标志。
* `ACK` 部分是对代理 `FIN` 包的确认(第二次挥手),表示:“好的,收到你准备关闭的请求了。”
* `FIN` 部分是客户端自己发起的关闭请求(第三次挥手),表示:“我(客户端)这边的数据也发完了,我也准备关闭了。”

* **No. 1900**: **第四次挥手**。代理服务器 `10.190.0.38` 回复客户端。
* 这是一个 `[ACK]` 包,用于确认收到了客户端的 `FIN` 请求。
* **分析**: 到这里,一个标准的、优雅的四次挥手过程就完成了。理论上,双方的连接已经和平关闭。

* **No. 1903**: 客户端 `192.168.33.167` 又发送了一个 `[RST]` 包。
* `RST` (Reset) 表示一个强制、异常的连接重置。
* **分析**: 这通常发生在一方收到了非预期的包,或者上层应用(浏览器)在连接关闭后仍然尝试使用该套接字,导致操作系统内核发送 RST 来强制终止。在这个场景下,它标志着这个 TCP 会话的彻底终结。

### 总结

1. **两层连接**: 整个过程包含两层连接。第一层是客户端与代理服务器之间的明文 TCP 连接,用于协商建立隧道。第二层是客户端与目标服务器(百度)之间的加密 TLS 连接,这条连接的数据“流经”第一层建立的隧道。

2. **代理的可见性**:
* **能看到**: 代理服务器知道客户端正在与哪个**域名 (`www.baidu.com`)** 和 **端口 (`443`)** 通信(从 `CONNECT` 请求中得知)。
* **看不到**: 代理服务器**无法**看到具体的通信内容,包括:
* 用户访问了哪个具体的 URL 路径 (例如 `/s?wd=keyword`)。
* HTTP 请求头和响应头的具体内容。
* 传输的任何 Cookie、表单数据或网页内容。

针对于https的流量解密可以看Wireshark解密HTTPS流量的两种方法

实验总结

在此次试验中,我使用了tinyproxy搭建了一个HTTP正向代理服务器,并使用客户端访问代理服务器,验证代理服务器是否正常工作。在代理服务器中抓包,分析使用HTTP代理服务器的通信过程。

参考链接

HTTP代理服务器实验

Linux环境使用Tinyproxy代理

Wireshark解密HTTPS流量的两种方法