【问题标题】:CONNECT request to a forward HTTP proxy over an SSL connection?通过 SSL 连接对转发 HTTP 代理的 CONNECT 请求?
【发布时间】:2011-09-29 11:48:08
【问题描述】:

我正在编写一个 HTTP 代理,但我无法理解通过 TLS 发出 CONNECT 请求的一些细节。为了更好地了解情况,我正在尝试使用 Apache 来观察它如何与客户端交互。这是来自我的默认虚拟主机。

NameVirtualHost *:443
<VirtualHost>
  ServerName example.com
  DocumentRoot htdocs/example.com  
  ProxyRequests On
  AllowConnect 22
  SSLEngine on
  SSLCertificateFile /root/ssl/example.com-startssl.pem
  SSLCertificateKeyFile /root/ssl/example.com-startssl.key
  SSLCertificateChainFile /root/ssl/sub.class1.server.ca.pem
  SSLStrictSNIVHostCheck off
</VirtualHost>

Apache 和我的客户之间的对话是这样的。

一个。客户端连接到example.com:443 并在 TLS 握手中发送example.com

b.客户端发送 HTTP 请求。

CONNECT 192.168.1.1:22 HTTP/1.1
Host: example.com
Proxy-Connection: Keep-Alive

c。阿帕奇说HTTP/1.1 400 Bad Request。 Apache 错误日志说

Hostname example.com provided via SNI and hostname 192.168.1.1
provided via HTTP are different. 

似乎 Apache 不查看 Host 标头,只是查看它的存在,因为 HTTP/1.1 需要它。如果客户端发送Host: foo,我会得到相同的失败行为。如果我在没有 TLS 的情况下向 example.com:80 发出 HTTP 请求,那么 Apache 会将我连接到 192.168.1.1:22。

我不完全理解这种行为。 CONNECT 请求有问题吗?我似乎找不到解释这一切的 RFC 的相关部分。

【问题讨论】:

  • 上面的 SNI 表示握手中发送的主机名,而不是主机头。正如我在下面的回答中所写,混合 SSL 和 CONNECT 代理并不典型。看起来 Apache 在进行证书验证时根本没有预料到这一点。您可以在 Apache 中尝试SSLStrictSNIVHostCheck off

标签: apache http ssl proxy


【解决方案1】:

不清楚您是否尝试使用 Apache Httpd 作为代理服务器,这可以解释您得到的 400 状态代码。 CONNECT 由客户端使用,并发送到代理服务器(可能是 Apache Httpd,但通常不是),而不是目标 Web 服务器。

CONNECT 在客户端和端服务器之间建立 TLS 连接之前在客户端和代理服务器之间使用。客户端(C)连接代理(P)proxy.example.com并发送此请求(包括空行):

C->P: CONNECT www.example.com:443 HTTP/1.1
C->P: Host: www.example.com:443
C->P:

代理打开到www.example.com:443 (P-S) 的 TCP 连接,并以 200 状态码响应客户端,接受请求:

P->C: 200 OK
P->C: 

此后,客户端和代理 (C-P) 之间的连接保持打开状态。代理服务器将 C-P 连接上的所有内容中继到 P-S。客户端通过在该通道上启动 TLS 握手,将其活动 (P-S) 连接升级为 SSL/TLS 连接。由于现在所有内容都被中继到服务器,就好像 TLS 交换是直接使用 www.example.com:443 完成的。

代理在握手中没有任何作用(因此与 SNI 无关)。 TLS 握手有效地直接发生在客户端和端服务器之间。

如果您正在编写代理服务器,您需要在CONNECT 请求中读取允许您的客户端连接到 HTTPS 服务器所需做的一切,建立从代理到终端服务器的连接(在 @ 987654331@ 请求),向客户端发送 200 OK 回复,然后将您从客户端读取的所有内容转发到服务器,反之亦然。

RFC 2616CONNECT 视为建立简单隧道的一种方式(它就是这样)。 RFC 2817 中有更多关于它的内容,尽管 RFC 2817 的其余部分(在非代理 HTTP 连接中升级到 TLS)很少使用。

看起来您正在尝试做的是通过 TLS 在客户端 (C) 和代理 (P) 之间建立连接。没关系,但客户端不会使用 CONNECT 连接到外部 Web 服务器(除非它也连接到 HTTPS 服务器)。

【讨论】:

  • 1) 想了解,当客户端可以直接使用 SSL 与终端服务器对话时,为什么还要使用 HTTP“CONNECT”?无论是“CONNECT”还是 SSL,它都会遍历配置的代理。 2)同样客户端在“CONNECT”请求中指定中间代理服务器地址是在哪个头域中的?
  • @Sandeep ,代理没有标头,而是客户端使用套接字目录连接到代理。这就是代理的意义
  • 那么,通过 CONNECT 方法,来自客户端的任何 https 数据都不会传递到中间代理的应用程序级别吗?并且只是在代理的 TCP 级别进行评估并直接中继到远程服务器?
【解决方案2】:

你做的一切都是对的。是 Apache 搞错了。最近才添加了对基于 TLS 的 CONNECT 的支持 (https://issues.apache.org/bugzilla/show_bug.cgi?id=29744),但仍有一些问题需要解决。您遇到的问题就是其中之一。

【讨论】:

    【解决方案3】:

    来自 RFC 2616(第 14.23 节):

    Host 请求头字段指定 Internet 主机和端口 被请求的资源的数量,从原始资源中获得 用户或引用资源给出的 URI(通常是 HTTP URL, 如第 3.2.2 节所述)。 Host 字段值必须代表 源服务器或网关的命名权限,由 原始网址。

    我的理解是您需要将地址从 CONNECT 行复制到 HOST 行。总而言之,资源的地址是 192.168.1.1,从 RFC 的角度来看,您通过 example.com 连接的事实并没有改变任何东西。

    【讨论】:

    • 根据5.2节,“2.如果Request-URI不是absoluteURI,并且请求中包含Host头域,则主机由Host头域值决定。”对于 CONNECT,Request-URI 不是 absoluteURI(第 5.1.2 节)。
    • @sigjuice ... 所以 5.2 不适用(你为什么提到它?)
    • 从 5.1.2 开始,“Request-URI = "*" | absoluteURI | abs_path | authority”。 CONNECT 使用 Request-URI 的授权形式。然后,从 5.2 “通过检查 Request-URI 和 Host 标头字段来确定 Internet 请求标识的确切资源。” IHMO,Apache 应该使用 Host 标头来确定主机,并且不会因错误“SNI 提供的主机和 HTTP 提供的主机不同(example.com vs 192.168.1.1)而失败。
    • @sigjuice 您将错误的变量(第 5.1 和 5.2 节)拉入方程。至于 Apache - 他们很可能在证书管理中使用 Host 标头,而不是太在意 RFC。
    • @sigjuice:按照我阅读第 14.23 节的方式,Host 标头必须用于指示所请求资源的主机。使用CONNECT 不属于Host 标头允许您选择应该处理CONNECT 的虚拟主机的类别:请求的资源仍然是客户端的最终目标。这也与第 14.23 节中指定的代理服务器 Host 的非 CONNECT 用法一致。我只是不认为代理主机本身的基于名称的选择是设想的。
    【解决方案4】:

    在 TLS (https) 中很少看到 CONNECT 方法。我实际上不知道有任何客户这样做(我很想知道它是做什么的,因为我认为这实际上是一个很好的功能)。

    通常客户端通过 http(纯 tcp)连接到代理并将 CONNECT 方法(和主机头)发送到主机:443。然后代理将与端点建立透明连接,然后客户端发送 SSL 握手。

    在这种情况下,数据是“端到端”受 ssl 保护的。

    CONNECT 方法并没有真正指定,它只是在 HTTP RFC 中保留。但通常它非常简单,因此可以互操作。该方法指定主机[:端口]。 Host: header 可以简单地忽略。可能需要一些额外的代理身份验证标头。当连接主体开始时,代理不再需要进行解析(有些会这样做,因为它们会检查有效的 SSL 握手)。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    相关资源
    最近更新 更多