Apache 在非默认虚拟主机上拒绝通过 SSL 进行 HTTP 连接

Apache 在非默认虚拟主机上拒绝通过 SSL 进行 HTTP 连接

我有一个运行多个虚拟主机的 apache 2.4.18 服务器。

/etc/apache2/sites-enabled/000-default.conf:

<VirtualHost *:80>
    DocumentRoot /var/www/html
    Redirect 400 /
</VirtualHost>

/etc/apache2/sites-enabled/000-default-ssl.conf:

<VirtualHost _default_:443>
    DocumentRoot /var/www/html
    SSLEngine on
    SSLCertificateFile      /etc/ssl/certs/ssl-cert-snakeoil.pem
    SSLCertificateKeyFile   /etc/ssl/private/ssl-cert-snakeoil.key
</VirtualHost>

/etc/apache2/sites-enabled/001-custom.conf:

<VirtualHost _default_:443>
    ServerName www.example.org

    Include /etc/apache2/letsencrypt/main.conf
    SSLCertificateFile      /etc/letsencrypt/live/example.org/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.org/privkey.pem

    Include /etc/apache2/proxytunnel/main.conf
</VirtualHost>

<VirtualHost *:80>
    ServerName www.example.org
    Redirect permanent / https://www.example.org/
</VirtualHost>

/etc/apache2/proxytunnel/main.conf:

ProxyRequests On
AllowConnect 2222
<Proxy *>
    Order deny,allow
    Deny from all
</Proxy>
<Proxy 127.0.0.1>
    Order deny,allow
    Allow from all
</Proxy>

我还在同一台机器的 2222 端口上运行一个 SSH 服务器。

如果我从远程计算机使用 proxytunnel 通过 SSL 访问 SSH 服务器,并使用 apache 作为代理服务器:

proxytunnel -v -E -p www.example.org:443 -d 127.0.0.1:2222

我收到以下错误:

SSL client to proxy enabled
Local proxy www.example.org resolves to xxx.xxx.xxx.xxx
Connected to www.example.org:443 (local proxy)

Tunneling to 127.0.0.1:2222 (destination)
Communication with local proxy:
 -> CONNECT 127.0.0.1:2222 HTTP/1.1
 -> Host: 127.0.0.1:2222
 -> Proxy-Connection: Keep-Alive
 <- HTTP/1.1 405 Method Not Allowed

HTTP return code: 405 Method Not Allowed
 <- Date: Thu, 14 Apr 2016 00:55:57 GMT
 <- Server: Apache/2.4.18 (Debian)
 <- Allow: GET,HEAD,POST,OPTIONS
 <- Content-Length: 309
 <- Content-Type: text/html; charset=iso-8859-1

但是如果我将该文件包含/etc/apache2/proxytunnel/main.conf在我的/etc/apache2/sites-enabled/000-default-ssl.conf虚拟主机中,它就可以工作......

SSL client to proxy enabled
Local proxy www.example.org resolves to xxx.xxx.xxx.xxx
Connected to www.example.org:443 (local proxy)

Tunneling to 127.0.0.1:2222 (destination)
Communication with local proxy:
 -> CONNECT 127.0.0.1:2222 HTTP/1.1
 -> Host: 127.0.0.1:2222
 -> Proxy-Connection: Keep-Alive
 <- HTTP/1.0 200 Connection Established

 <- Proxy-agent: Apache/2.4.18 (Debian)

 Tunnel established.
 SSH-2.0-OpenSSH_7.2p2 Debian-2

因此,我的结论是,要使 CONNECT 请求通过 SSL 在 apache 服务器上工作,AllowCONNECT除了发出请求的实际 vhost 之外,还必须将指令放在 apache 代理端口的默认 vhost 中。

请注意,使用 HTTP 上的 CONNECT(而不是 HTTPS)且在代理隧道中禁用加密时,不会重现此行为。此外,问题并非来自代理隧道,因为请求已正确转发到 apache 并出现在服务器日志中:是 apache 主动拒绝了它,因为它认为 HTTP 方法(CONNECT)在此服务器上无效(尽管在相关的虚拟主机中允许)。

答案1

此外,问题不是来自代理隧道,因为请求被正确转发到 apache,并且出现在服务器日志中

这是错误的,在我使用的版本中,proxytunnel 不支持 SNI(最新提交从本文发布之日起从他们的存储库中提取,所以如果我相信他们的发布标签的话,这个版本比 1.9.1 稍微早一点)。

结果是,无论我尝试连接到哪个主机,apache 选择的 vhost 都是默认 vhost。

答案2

我想根据自己的经验提供反馈来补充这个问题。我还不能发表评论。

我在 Windows 7 上使用 Proxytunnel 1.9.9(大约 2018 年 4 月),它是我使用 Cygwin 32 位从源代码编译的。

经过测试,我发现 Proxytunnel 无法将 -p 参数中的主机名与 Apache2 Virtualhost 中的 ServerName 正确匹配。使用 Proxytunnel 通过一个 http 或 https 本地代理建立隧道会失败,除非包含 AllowCONNECT 方法的虚拟主机是默认虚拟主机。

列出 Apache 中启用的虚拟主机并查看哪个是默认的:

apachectl -S

在我的设置中,我将每个虚拟主机放在 sites-available 目录中的自己的文件中。运行以下命令:

ls -1

sites-available 目录中列出的第一个文件是 apache2 将设为默认虚拟主机的虚拟主机。这样,我将 http(或 https)正向代理替换为默认和第二行虚拟主机...通过更改其名称,使其不会出现在目录列表中的第一个。

我发现这个用于 http 本地代理的命令:

proxytunnel -v -p http-forward-proxy.com:80 -d 192.168.0.10:22

或者对于 https 本地代理使用此命令:

proxytunnel -v -E -C root.pem https-forward-proxy.com:443 -d 192.168.0.10:22

如果 AllowCONNECT 方法在默认虚拟主机中,则给我 OpenSSH 横幅,否则,给我 HTTP 405 错误...即使非默认端口 80 虚拟主机包含:

ServerName http-forward-proxy.com

或者在代理到 https 正向代理的情况下,当非默认端口 443 虚拟主机包含以下内容:

ServerName https-forward-proxy.com

我查看了 Apache2 日志并确认处理总是转到默认虚拟主机。

我还在 Proxytunnel GitHub 页面上发布了有关 HTTP 案例的“问题” https://github.com/proxytunnel/proxytunnel/issues/31

然而

我使用带有 sslh 的 Proxytunnel 客户端和 stunnel 服务器端。在这种情况下,我发现 Proxytunnel 命令中的主机名与 sslh 中的 sni_hostnames{} 功能匹配,因此在这种情况下,主机名似乎至少在加密和使用 SNI 时传输正确。

答案3

感谢您提出问题并写下结论。我现在有一个可用的设置,感谢您!使用 apache 默认 vhost 效果很好。

不过,我想知道 proxytunnel 的 SNI 是否真的是问题所在。就我而言,我有https://app1.example.com这是 apache 的默认虚拟主机和另一个虚拟主机https://example.com。我的 letsencrypt 证书的 commonname 是 app1.example.com,subjectaltname 是 example.com。

如果我将其添加ProxyRequests on到 example.com,它根本不起作用。如果我将其移动到 app1.example.com,它就可以正常工作。

据我了解,如果多个虚拟主机在单个 IP 上使用一个证书,则不需要 SNI。

另外,我使用 curl 进行测试,如curl -v -x https://example.com https://somethingelse.com。 Curl 支持 SNI,我使用 wireshark 检查过:它确实在握手扩展中为 CONNECT 请求和 GET 请求发送了正确的主机名。我仍然得到405 Method Not Allowed

因此,问题似乎出在 mod_proxy 未正确激活。您认为呢?

我在使用 apache 2.4.25。

相关内容