【问题标题】:How to forward HTTPS traffic from a SOCKS proxy to HTTP proxy如何将 HTTPS 流量从 SOCKS 代理转发到 HTTP 代理
【发布时间】:2018-02-22 20:15:38
【问题描述】:

我编写了一个 SOCKS 代理,如果链接关闭,它可以同时处理 HTTP 和 HTTPS 流量。

如果启用了链接并且转发主机和端口属于过滤 HTTP 代理,则只有 HTTP 流量可以流动。 HTTPS 流量不流动并报告 SSL 错误。

请注意,当请求直接来自浏览器而不是来自 SOCKS 服务器时,HTTP 代理会处理 HTTPS 流量。

例如,如果我向https://www.google.com 发出请求,则会发生以下情况:

1) 客户端发送一个 SOCKS 5 问候语,让我们知道哪些身份验证方法是可接受的。

2) 服务器响应 NO_AUTH

3) 客户端发送连接请求(包括预期的目标主机和端口)。

4) 服务器创建一个套接字并将其连接到 HTTP 代理服务器,并以 GRANTED 响应客户端

5) SOCKS 服务器然后收到以下请求(不可见/控制字符已全部替换为其字符代码,因此您可以看到发生了什么):

\u0016\u0003\u0001\u0000Ñ\u0001\u0000\u0000Í\u0003\u0003áp¥@Ia¹\u0001„Ä\u0006 É;š‰‰4\u001dýà•J>Ü6¢Þ\fö\u001c%\u0000\u0000(À+À/\u0000žÌ\u0014Ì\u0013À\nÀ\tÀ\u0013À\u0014À\u0007À\u0011\u00003\u00002\u00009\u0000œ\u0000/\u00005\u0000\n\u0000\u0005\u0000\u0004\u0001\u0000\u0000|\u0000\u0000\u0000\u0013\u0000\u0011\u0000\u0000\u000ewww.google.comÿ\u0001\u0000\u0001\u0000\u0000\n\u0000\b\u0000\u0006\u0000\u0017\u0000\u0018\u0000\u0019\u0000\u000b\u0000\u0002\u0001\u0000\u0000#\u0000\u00003t\u0000\u0000\u0000\u0010\u0000\u001b\u0000\u0019\u0006spdy/3\bspdy/3.1\bhttp/1.1uP\u0000\u0000\u0000\u0005\u0000\u0005\u0001\u0000\u0000\u0000\u0000\u0000\u0012\u0000\u0000\u0000\r\u0000\u0012\u0000\u0010\u0004\u0001\u0005\u0001\u0002\u0001\u0004\u0003\u0005\u0003\u0002\u0003\u0004\u0002\u0002\u0002

如您所见,它完全不可读,但我们已经从初始 SOCKS 连接消息(第 3 步)知道用户打算去哪里,因此我们可以创建并发出以下连接请求:

CONNECT www.google.com:443 HTTP/1.1\r\nUser-Agent: MySocksServer\r\nProxy-Connection: keep-alive\r\nHost: www.google.com\r\n\r\n

6) 这个新构建的 CONNECT 被发送到我们链接的 HTTP 代理,该代理检查其过滤规则并响应:

HTTP/1.1 200 Connection Established\r\nVia: 1.1 HTTPserverName\r\nX-WebMarshal-RequestID: AN_ID_STRING\r\n\r\n

7) 这是在我们的 SOCKS 服务器中接收的,并被转发(未修改)到客户端。在我的调试中,我在发送请求之前直接监控套接字,并且可以看到客户端套接字已连接。

8) 引发的下一个事件是错误,带有错误 SOCKET_NOT_CONNECTED,对套接字运行另一次检查确认客户端套接字确实不再连接。

为什么我的 Socket 会在第 7 步和第 8 步之间关闭?我没有正确遵循协议吗?我看不到我错过了什么。我想我在某种程度上处理了 CONNECT 方法错误?

如果我不修改 SOCKS 服务器收到的请求(即将其转换为 CONNECT 请求),而是将不可读的数据直接转发到 HTTP 代理,那么 HTTP 代理的日志会显示:

Badly formated request: \u0016\u0003\u001
Bad request received.

Failed to read request: Client closed connection. (0)
1Request took 0 ms + 23 ms idle time

【问题讨论】:

    标签: sockets http network-programming network-protocols socks


    【解决方案1】:

    正确的顺序是:

    1. 客户端连接到 SOCKS 代理,根据需要进行身份验证。

    2. 客户端发送 SOCKS 连接请求以创建到 www.google.com:443 的隧道。

    3. SOCKS 代理连接到 HTTP 代理

    4. SOCKS 代理发送 HTTP CONNECT 请求以创建到 www.google.com:443 的隧道。

    5. SOCKS 代理收到来自 HTTP 代理的回复。

    6. SOCKS 代理向客户端发送适当的 SOCKS 回复。

    7. 如果 HTTP 代理成功,则在客户端和 HTTP 代理之间传递未修改的数据,直到其中一个断开连接。

    8. 关闭客户端连接和 HTTP 代理连接。

    当您链接代理时,您必须先协商隧道,然后才能开始通过它们传递应用程序数据。在下一个代理首先回复其隧道状态之前,不要向客户端发送隧道回复。

    【讨论】:

    • 此提议仅在 HTTP 和 HTTPS 的 socks 代理不同时才有效,因为在第 1 步之后您不知道来自客户端的请求是 HTTPS(需要 CONNECT)还是 GET|POST (需要重写请求行中的 URL)。但是,浏览器通常只允许您配置一个用于所有协议的 socks 代理。
    • SOCKS 代理不需要知道它是否是 HTTPS。这同样适用于 HTTP 和 HTTPS。当客户端启动其 SSL 握手时,该数据需要按原样直接发送到目标 HTTPS 服务器。隧道不关心数据是 HTTP、SSL 还是 PNG 或其他任何东西,它们只是透明的传递。客户端要求 SOCKS 代理连接到某个主机/端口。时期。 SOCKS 代理请求 HTTP 代理连接到相同的主机/端口。时期。以此类推,直到到达主机/端口(或发生错误)。
    • 是和不是。大多数代理会忽略隧道的内容,您的解决方案适用于这些内容。但是防火墙上的代理通常会进行 SSL 检查,并且不会让非 SSL 流量通过隧道。在这些情况下,您需要有一个真正的 http 代理,而不是只为所有事情使用隧道。然后你需要检测协议并以不同的方式处理http和https。
    • 但在 SOCKS 代理成功回复客户端并成功响应客户端的连接请求之前,客户端不会发送其 SSL 握手,因此 SOCKS 代理无需检查任何内容。在 SOCKS 代理表示隧道已首先建立之前,客户端不应发送任何内容。所以你说的只有当 SOCKS 代理在收到 HTTP 代理回复之前回复客户端时才有效。
    • 是的,你是对的。 socks 服务器必须先接受连接,然后才能获得必要的数据来确定应用程序协议。但在最初的问题(第 4 步)中似乎就是这种情况。
    【解决方案2】:

    6) 这个新构建的 CONNECT 被发送到 HTTP 代理……这个代理……响应:

    7) 这在我们的 SOCKS 服务器中接收并被转发(未修改)到客户端...

    这是错误的。您在 SOCKS 代理中生成 CONNECT 请求,因此您应该将此请求的响应留给自己,而不是转发给客户端。你应该做什么:

    • 如果您从客户端收到 SSL 握手的开始(“\x16\x03...”),您应该缓冲它。
    • 然后创建 CONNECT 请求并将其发送到代理。 Host 标头和 Proxy-Connection 标头对 CONNECT 没有任何意义,因此您无需添加它们。
    • 读取代理对 CONNECT 请求的响应。如果状态码不是 200 有问题,您应该关闭与客户端的连接。没有简单的方法将错误信息传递给客户端。
    • 如果状态码为 200,则通过代理将缓冲的 ClientHello 从客户端转发到服务器,然后在客户端和服务器之间转发所有内容(通过代理隧道)。

    【讨论】:

    • 第一步不需要缓冲。没有什么要读的,因为在 SOCKS 连接报告成功之前,客户端不应该发送任何 HTTP(S) 或 SSL 数据,而在 HTTP 代理首先响应之前它不应该这样做。
    • @RemyLebeau:如果我正确理解问题,SOCKS 服务器应该将 HTTP(s) socks 请求转换为 HTTP(s) 代理请求。因此,socks 服务器对于 HTTP 和 HTTPS 是相同的,您必须通过连接的初始字节来区分它是纯 HTTP(例如 GET、POST...)还是 HTTPS(“\x16\x03...” ),因为您需要以不同的方式处理这些情况。
    • 你理解错了。 SOCKS 代理不需要对它们进行不同的处理。它甚至根本不需要查看 HTTP(S) 数据。看我的回答。
    • @RemyLebeau:我不认为(还)我理解错了。浏览器不允许您为 http 和 https 配置不同的 socks 代理,因此 socks 代理本身必须检测协议,因为 http 和 https 需要以不同方式处理(请参阅您的回复中的评论)。
    • SOCKS 的工作方式相同,无论通过它的协议如何。袜子不在乎。这就是浏览器和其他客户端应用程序不为 HTTP 和 HTTPS 提供单独代理设置的原因。 HTTP 和 HTTPS 不需要在 SOCKS 中进行不同的处理。 IF SOCKS 代理需要区分,比如链接到另一个已知实现 HTTP 和 HTTPS 不同的代理时,差异在 SOCKS 端透明处理,客户端不需要知道,并且不需要为 HTTP 和 HTTPS 单独设置代理。
    猜你喜欢
    • 1970-01-01
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-12
    • 1970-01-01
    相关资源
    最近更新 更多