Apache 通过SSL连接将请求连接到转发HTTP代理?

Apache 通过SSL连接将请求连接到转发HTTP代理?,apache,http,ssl,proxy,Apache,Http,Ssl,Proxy,我正在编写HTTP代理,在理解通过TLS发出连接请求的一些细节时遇到困难。为了更好地了解情况,我正在使用Apache进行实验,以观察它如何与客户机交互。这是来自我的默认虚拟主机 NameVirtualHost *:443 <VirtualHost> ServerName example.com DocumentRoot htdocs/example.com ProxyRequests On AllowConnect 22 SSLEngine on SSLC

我正在编写HTTP代理,在理解通过TLS发出连接请求的一些细节时遇到困难。为了更好地了解情况,我正在使用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>
c。Apache说HTTP/1.1400请求不正确。Apache错误日志显示

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


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

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

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

代理打开到
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握手有效地直接发生在客户端和终端服务器之间

如果您正在编写代理服务器,则允许客户端连接到HTTPS服务器所需执行的所有操作都将在
connect
请求中读取,从代理服务器连接到终端服务器(在
connect
请求中给出),向客户端发送
200 OK
回复,然后将从客户端读取的所有内容转发给服务器,反之亦然

CONNECT
视为建立简单隧道的一种方法(实际上是这样的)。虽然RFC2817(在非代理HTTP连接中升级到TLS)的其余部分很少使用,但中有更多内容

看起来您试图做的是通过TLS在客户端(C)和代理(p)之间建立连接。这很好,但是客户端不会使用
CONNECT
连接到外部web服务器(除非它也是到HTTPS服务器的连接)。

来自RFC 2616(第14.23节):

主机请求标头字段指定Internet主机和端口 从原始文件中获取的被请求资源的编号 用户或引用资源提供的URI(通常是HTTP URL, 如第3.2.2节所述)。主机字段值必须表示 由指定的源服务器或网关的命名权限 原始网址


我的理解是,您需要将地址从连接线复制到主机线。总之,资源的地址是192.168.1.1,从RFC的角度来看,您通过example.com进行连接的事实不会改变任何东西

在TLS(https)中很少看到连接方法。实际上,我不知道有哪个客户会这么做(我想知道是谁做的,因为我认为这实际上是一个很好的特性)

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

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


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

您做的一切都是正确的。是阿帕奇搞错了。最近才添加了对通过TLS连接的支持(),还有一些事情需要解决。您遇到的问题就是其中之一。

根据第5.2节,“2.如果请求URI不是绝对URI,并且请求包含主机标头字段,则主机由主机标头字段值确定。”对于CONNECT,请求URI不是绝对URI(第5.1.2节)。@sigjuice。。。因此,5.1.2中的“请求URI=“*”|绝对URI | abs|u路径| authority”不适用于5.1.2中的5.2(为什么您引用了它?)。CONNECT使用请求URI的授权形式。然后,从5.2开始,“通过检查请求URI和主机头字段来确定由Internet请求标识的确切资源。”IHMO、Apache应使用主机头来确定主机,并且不会出现错误“SNI提供的主机和HTTP提供的主机不同(example.com vs 192.168.1.1)@sigjuice您将错误的变量(第5.1节和第5.2节)拉入等式中。至于Apache-他们很可能在证书管理中使用主机标头,而不太关心RFC。@sigjuice:按照我阅读第14.23节的方式,
Host
标头必须用于指示请求资源的主机。使用<
C->P: CONNECT www.example.com:443 HTTP/1.1
C->P: Host: www.example.com:443
C->P:
P->C: 200 OK
P->C: