与远程服务器进行 SSL 握手期间出错

Posted

技术标签:

【中文标题】与远程服务器进行 SSL 握手期间出错【英文标题】:Error during SSL Handshake with remote server 【发布时间】:2013-09-23 05:27:46 【问题描述】:

我有Apache2(在 443 上收听)和一个在 Ubuntu 上运行的网络应用程序 Tomcat7(在 8443 上收听)。

我将 apache2 设置为反向代理,以便通过端口 443 而不是 8443 访问 Web 应用程序。此外,我不仅需要在浏览器和 apache2 之间进行 SSL 通信,还需要在 apache2 和 tomcat7 之间进行 SSL 通信,因此我在两者上都设置了 SSL apache2和tomcat7。 如果我尝试通过直接联系 tomcat7 来访问 Web 应用程序,一切都很好。 问题是当我尝试通过apache2(反向代理)访问tomcat的web应用时,在浏览器上出现错误:

Proxy Error
The proxy server could not handle the request GET /web_app.
Reason: Error during SSL Handshake with remote server

【问题讨论】:

Apache 不验证您在 tomcat 上安装的证书。它是自签名证书吗?还是由内部 CA 制作? 使用以下命令自签名:openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt serverfault.com/questions/356678/… 我想这就是你想要的: SSLProxyVerify none SSLProxyCheckPeerCN off 最好将 SSLProxyCACertificateFile 设置为您的私有 CA 证书,而不是仅仅关闭验证。 如this blog 中所述,您可以关闭 SSL 检查。 【参考方案1】:

MK 的评论为我指明了正确的方向。

对于 Apache 2.4 及更高版本,有不同的默认值和新指令。

我正在运行 Apache 2.4.6,我必须添加以下指令才能使其正常工作:

SSLProxyEngine on
SSLProxyVerify none 
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off

【讨论】:

所以这会关闭保护,但只要流量是本地的(即127.0.0.1:8443),问题应该不大,对吧? 嗯,它不会关闭保护,因为涉及到加密。流量仍然是加密的。这只是禁用了对证书的检查,以确保它是由受信任的权威机构提供的。因此,如果您信任服务器,则应该没有问题。但是,是的,对于本地交通,我认为你也很好。 感谢 mydoghasworms。您的指令适用于服务器版本:Apache/2.4.6。如果有人需要知道 httpd 的版本,请使用:httpd -V 我刚刚在 Apache 2.4.29 上遇到了 AH01097 错误,所以有些类似于原始问题。我将以上所有内容添加到我的/etc/apache2/apache2.conf 文件中,并通过它们来查看哪些内容有所不同。就我而言,SSLProxyCheckPeerExpire off 是握手最终成功的原因。 这帮助我设置了我的 HTTP 到 HTTPS 映射反向代理。请在下面的答案中参考我的详细说明,因为 cmets 有字符限制。【参考方案2】:

我在 docker、反向代理和 Web 服务器上设置了 2 台服务器。 一年后,我的所有网站突然开始发生此错误。 之前设置时,我在网络服务器上生成了一个自签名证书。

所以,我不得不再次生成 SSL 证书,它才开始工作......

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ssl.key -out ssl.crt

【讨论】:

【参考方案3】:

遇到了和 OP 一样的问题:

通过 SOAP UI 直接访问时,Tomcat 返回响应 没有加载 html 文件 使用上一个答案提到的 Apache 属性时,出现网页但 AngularJS 无法获得 HTTP 响应

Tomcat SSL 证书已过期,而浏览器显示它是安全的 - Apache 证书还远未过期。更新 Tomcat KeyStore 文件解决了这个问题。

【讨论】:

【参考方案4】:

在远程 OEL (Oracle Enterprise Linux) 7.8 服务器上,我有一个使用 HTTPS/8009 运行的后端 Web 应用程序。作为第三方应用,我没有选择禁用 SSL 或更改端口。

由于我需要从本地计算机的浏览器访问 Web 应用程序,我想到了使用 Apache httpd 设置反向代理(HTTP 到 HTTPS 映射)。现在我可以通过以下 URL 从本地浏览器访问网络应用程序:

http://10.157.146.97:1234/

仅供参考,在 Linux 机器中运行的 CURL 命令如下:

curl http://10.157.146.97:1234/
curl -k https://localhost:8009/

这是我的反向代理设置:

/etc/httpd/conf/httpd.conf

Listen 1234

<VirtualHost *:1234>
SSLProxyEngine On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
ProxyPreserveHost On
ProxyPass / https://localhost:8009/
ProxyPassReverse / https://localhost:8009/
</VirtualHost>

在一个方面我很挣扎,早些时候我尝试在 ProxyPass/ProxyPassReverse 中使用 url 模式(/sample),但这导致 css/js 文件出现 HTTP 404(未找到),因为 web 应用程序的欢迎页面包含间接 css/ js 路径(下面的示例代码)。所以用 (/) 替换 url 模式 (/sample) 也解决了这个问题。

previous Not working config:
ProxyPass /sample https://localhost:8009/
ProxyPassReverse /sample https://localhost:8009/

<script defer src="abc.js"></script><link href="xyz.css" rel="stylesheet"></head>  

【讨论】:

【参考方案5】:

请注意,当您的系统禁用 TLSv1 时,也可能会发生该错误。例如,Ubuntu 20.x 默认禁用 TLSv1.0。例如,如果你有这样的事情:

Apache 2.4.41 on Ubutntu20 (proxy) --[https]--> old Apache serving TLS v1.0

SSLProxyVerify不会帮助你。

您需要做的是在openssl.conf 中启用 TLS 1.0。至少在您可以更新旧服务器之前 ?...

在 Ubuntu 上启用旧 TLS

所以在 Ubuntu 20.04.3 TLS 中有效启用 TLSv1 更改 /etc/ssl/openssl.cnf。在文件顶部(任何部分之前)添加:

# Added to enable TLS1.0
openssl_conf = default_conf

在文件的最后

##
# Added to enable TLS1.0
[default_conf]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
CipherString = DEFAULT@SECLEVEL=1
##

注释显然不是必需的 ?,但在您想再次禁用 TLS1 时会有所帮助。

重启/重启后一切正常。

请注意,这是一个全局(系统范围)更改。所以它并不理想,但它确实有效。另见:more notes about Ubuntu and default TLS versions。

【讨论】:

您的解决方案存在几个问题:1. 您没有更改协议设置,但密码套件列表(MinProtocolMaxProtocol 更改了协议),2. 您是使用 OpenSSL 更改所有软件的默认配置,而不仅仅是代理连接的设置, 3. 大多数软件(包括 Apache2)总是覆盖这些默认设置。对于 Apache2,请参阅 SSLProxyProtocol 指令。 好吧,当我从 Ubuntu 18 升级到 20 时,它开箱即用。而且我不必在我的 Apache conf 中更改 anything。而且curl 也开始工作(在此更改之前,它报告了“不支持的协议”)。所以它确实改变了支持的协议versions。但是,是的,您说得对,这种变化是全球性的。 我检查了,我有代理协议的默认设置,所以 SSLProxyProtocol all -SSLv3 包括 TLS1.0。并且仍然无法从 Ubuntu 20 连接到 tls1 服务器。 我错误地认为 Ubuntu 和 Debian 的 openssl 软件包是同步的。 Debian 选择 add a MinProtocol default 到 openssl.cnf,而 Ubuntu 选择了更激进的解决方案,并将最低版本 1.2 硬编码到 security level 2。【参考方案6】:

这是我对这个主题的变体,灵感来自this Git gist。服务器是一个带有内部自签名 SSL 证书的 Docker 容器,可通过https://localhost:8443 访问。代理到server.example.org:443。相关配置详情:

<VirtualHost AAA.BBB.CCC.DDD:443>
    ServerName server.example.org

    ErrorLog $APACHE_LOG_DIR/error.log
    CustomLog $APACHE_LOG_DIR/access.log combined

    # These settings are definitely needed
    SSLEngine On
    SSLProxyEngine On
    ProxyRequests Off
    SSLProxyVerify none 
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off

    # These may not be needed, depending on proxied application
    ProxyPreserveHost on
    RequestHeader set X-Forwarded-Proto https

    ProxyPass "/" "https://localhost:8443/"
    RewriteEngine on
    RewriteCond %HTTP:Upgrade websocket [NC]
    RewriteCond %HTTP:Connection upgrade [NC]
    RewriteRule ^/?(.*) "wss://localhost:8443/$1" [P,L]
    ProxyPassReverse "/" "https://localhost:8443/"
</VirtualHost>

SSLEngine OnRequestHeader... 之间的部分是我通过谷歌搜索和反复试验拼凑而成的。也许其中一些设置是不需要的,YMMV。

注意:需要 RewriteRule"wss",因为服务器使用安全 websocket。

平台:Ubuntu 20.04.3 LTS、Apache 2.4.41。

【讨论】:

以上是关于与远程服务器进行 SSL 握手期间出错的主要内容,如果未能解决你的问题,请参考以下文章

与服务器成功建立连接,但在登录前握手期间发生错误。 (提供者:SSL 提供者,错误:0

已成功与服务器建立连接,但是在登录前的握手期间发生错误

已成功与服务器建立连接,但是在登录前的握手期间发生错误。 (provider: SSL Provider, error: 0 - 等待的

javax.net.ssl.SSLHandshakeException:在 jdk 6 中握手期间远程主机关闭连接

AWS EB:WebSocket 握手期间出错:意外响应代码:400

javax.net.ssl.SSLHandshakeException:握手期间远程主机关闭连接