You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用IO::Socket::SSL经HTTP隧道代理连接HTTPS服务的可行方案

软件环境

自行编译部署的Perl-5.34.1(非perlbrew环境)
Net-SSLeay 1.92
IO-Socket-SSL 2.074

抱歉无法提供pastebin链接,当前位置无相关访问权限

当前使用的“代理隧道”为HTTP协议,但本地防火墙规则要求所有连接必须以HTTPS方式发起。
此前尝试两种方案规避问题:一是通过IO::Socket::INET建立普通连接后升级为SSL连接,二是创建SSL套接字时不立即握手、延后执行握手流程,两种方案均无法解决代理隧道连接异常,因此推测该场景需要使用独立套接字实现。

问题

如何使用IO::Socket::SSL(可搭配其他CPAN模块)实现HTTP代理隧道场景下的HTTPS服务正常连接?希望尽可能避免使用LWP::UserAgent,目前暂未在CPAN上找到可解决该问题的相关模块。

测试示例

(1) curl --verbose 测试

在RHEL6平台尝试通过内网防火墙连接目标HTTPS服务,该服务为用于验证SSL连通性的“hello world”测试服务,内网其他主机上的Firefox浏览器可正常访问(与本次IO::Socket::SSL测试主机非同台设备)。使用curl连接失败,返回代理隧道相关报错(主机名、IP已做脱敏处理),执行日志如下:

curl --verbose 'https://foo.bar.net/bim/bam'
*   Trying 10.10.10.10...
* Connected to 10.10.10.10 (10.10.10.10) port 80 (#0)
* Establish HTTP proxy tunnel to foo.bar.net:443
> CONNECT foo.bar.net:443 HTTP/1.1
> Host: foo.bar.net:443
> User-Agent: curl/7.44.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 503 Service Unavailable
< Cache-Control: no-cache
< X-XSS-Protection: 1
< Connection: close
< Content-Type: text/html; charset=utf-8
< Content-Length: 750
< Pragma: no-cache
< Set-Cookie: frobnicate; path=/; Httponly
<
* Received HTTP code 503 from proxy after CONNECT
* Closing connection 0
curl: (56) Received HTTP code 503 from proxy after CONNECT
(2) 单独使用IO::Socket::SSL测试

代理隧道并非透明模式,直接创建IO::Socket::SSL套接字连接失败,调试日志如下:

$IO::Socket::SSL::DEBUG = 3;
IO::Socket::SSL->new
(
    PeerAddr    => $auth
  , PeerPort    => 'https'
)

对应调试输出:

DB<1>
  DEBUG: .../IO/Socket/SSL.pm:2961: new ctx 54179840
  DEBUG: .../IO/Socket/SSL.pm:704: socket not yet connected
  DEBUG: .../IO/Socket/SSL.pm:706: socket connected
  DEBUG: .../IO/Socket/SSL.pm:729: ssl handshake not started
  DEBUG: .../IO/Socket/SSL.pm:771: using SNI with hostname foo.bar.com
  DEBUG: .../IO/Socket/SSL.pm:806: request OCSP stapling
  DEBUG: .../IO/Socket/SSL.pm:836: call Net::SSLeay::connect
  DEBUG: .../IO/Socket/SSL.pm:2852: did not get stapled OCSP response
  DEBUG: .../IO/Socket/SSL.pm:2805: ok=0 [0] /C=US/O=DigiCert Inc/CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1/C=US/ST=New York/L=Someplace/O=Foo Bar, Inc./CN=foo.bar.com
  DEBUG: .../IO/Socket/SSL.pm:839: done Net::SSLeay::connect -> -1
  DEBUG: .../IO/Socket/SSL.pm:842: SSL connect attempt failed

  DEBUG: .../IO/Socket/SSL.pm:842: local error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
  DEBUG: .../IO/Socket/SSL.pm:845: fatal SSL error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
  DEBUG: ...inux/IO/Socket.pm:50: ignoring less severe local error 'IO::Socket::IP configuration failed', keep 'SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed'
  DEBUG: .../IO/Socket/SSL.pm:3010: free ctx 54179840 open=
  DEBUG: .../IO/Socket/SSL.pm:3014: free ctx 54179840 callback
  DEBUG: .../IO/Socket/SSL.pm:3021: OK free ctx 54179840
  not ok 1 - Direct: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed.

IO::Socket::SSL的POD文档中提供了两种可能规避该问题的方案,分别测试如下:

(3) INET套接字升级为SSL方案

方案示例代码:

my $sock = IO::Socket::INET->new(...) or die $!;
IO::Socket::SSL->start_SSL($sock,%sslargs) or die $SSL_ERROR;
$sock->stop_SSL or die $SSL_ERROR;

实际测试代码:

my $sock
= IO::Socket::INET->new
(
    PeerAddr    => $auth
  , PeerPort    => 'https'
)
or die "INET: $IO::Socket::errstr\n";

IO::Socket::SSL->start_SSL
(
    $sock
  , 'PeerPort'  => 'https'
)
or die "SSL: $SSL_ERROR\n";

对应调试日志:

DB<1>
  DEBUG: .../IO/Socket/SSL.pm:2961: new ctx 58865232
  DEBUG: .../IO/Socket/SSL.pm:1561: start handshake
  DEBUG: .../IO/Socket/SSL.pm:729: ssl handshake not started
  DEBUG: .../IO/Socket/SSL.pm:774: not using SNI because hostname is unknown
  DEBUG: .../IO/Socket/SSL.pm:806: request OCSP stapling
  DEBUG: .../IO/Socket/SSL.pm:836: call Net::SSLeay::connect
  DEBUG: .../IO/Socket/SSL.pm:2852: did not get stapled OCSP response
  DEBUG: .../IO/Socket/SSL.pm:2805: ok=0 [0] /C=US/O=DigiCert Inc/CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1/C=US/ST=New York/L=Edgewood/O=Foo Bar, Inc./CN=foo.bar.com
  DEBUG: .../IO/Socket/SSL.pm:839: done Net::SSLeay::connect -> -1
  DEBUG: .../IO/Socket/SSL.pm:842: SSL connect attempt failed

  DEBUG: .../IO/Socket/SSL.pm:842: local error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
  DEBUG: .../IO/Socket/SSL.pm:845: fatal SSL error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
  DEBUG: .../IO/Socket/SSL.pm:1984: downgrading SSL only, not closing socket
  DEBUG: .../IO/Socket/SSL.pm:3010: free ctx 58865232 open=
  DEBUG: .../IO/Socket/SSL.pm:3014: free ctx 58865232 callback
  DEBUG: .../IO/Socket/SSL.pm:3021: OK free ctx 58865232
  BRCC::FM::Test::(bin/socket-check:55):
(4) 延迟SSL握手方案

创建SSL套接字时设置不立即握手,连接建立后手动触发握手,测试代码如下:

my $sock
= IO::Socket::SSL->new
(
    PeerAddr            => $auth
  , PeerPort            => 'https'
  , SSL_startHandshake  => 0
)
or die "SSL: $SSL_ERROR";

$sock->connect_SSL
or die "Connect: $SSL_ERROR";

对应调试日志:

DB<1>
DEBUG: .../IO/Socket/SSL.pm:2961: new ctx 43293280
DEBUG: .../IO/Socket/SSL.pm:704: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:706: socket connected
BRCC::FM::Test::(bin/socket-check:50):
50:             $sock->connect_SSL
51:             or die "Connect: $SSL_ERROR";
  DB<1>
DEBUG: .../IO/Socket/SSL.pm:729: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:771: using SNI with hostname foo.bar.com
DEBUG: .../IO/Socket/SSL.pm:806: request OCSP stapling
DEBUG: .../IO/Socket/SSL.pm:836: call Net::SSLeay::connect
DEBUG: .../IO/Socket/SSL.pm:2852: did not get stapled OCSP response
DEBUG: .../IO/Socket/SSL.pm:2805: ok=0 [0] /C=US/O=DigiCert Inc/CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1/C=US/ST=New York/L=Edgewood/O=Foo Bar, Inc./CN=foo.bar.com
DEBUG: .../IO/Socket/SSL.pm:839: done Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:842: SSL connect attempt failed

DEBUG: .../IO/Socket/SSL.pm:842: local error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:845: fatal SSL error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:3010: free ctx 43293280 open=
DEBUG: .../IO/Socket/SSL.pm:3014: free ctx 43293280 callback
DEBUG: .../IO/Socket/SSL.pm:3021: OK free ctx 43293280
(5) 关闭证书验证+自动握手测试

设置SSL_verify_mode为0关闭证书验证、开启自动握手,仍未连接成功,测试代码如下:

my $sock
= IO::Socket::SSL->new
(
    PeerAddr            => $auth
  , PeerPort            => 'https'
  , SSL_startHandshake  => 1
  , SSL_verify_mode     => 0
)
or die "SSL: $SSL_ERROR";

对应调试日志:

DB<1>
  DEBUG: .../IO/Socket/SSL.pm:2537: new ctx 50291120
  DEBUG: .../IO/Socket/SSL.pm:529: socket not yet connected
  DEBUG: .../IO/Socket/SSL.pm:531: socket connected
  DEBUG: .../IO/Socket/SSL.pm:553: ssl handshake not started
  DEBUG: .../IO/Socket/SSL.pm:586: using SNI with hostname foo.bar.com
  DEBUG: .../IO/Socket/SSL.pm:653: Net::SSLeay::connect -> -1
  DEBUG: .../IO/Socket/SSL.pm:1769: SSL connect attempt failed

  DEBUG: .../IO/Socket/SSL.pm:1774: SSL connect attempt failed error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
  DEBUG: .../IO/Socket/SSL.pm:659: fatal SSL error: SSL connect attempt failed error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
  DEBUG: .../IO/Socket/SSL.pm:1758: IO::Socket::INET configuration failed
  DEBUG: .../IO/Socket/SSL.pm:2570: free ctx 50291120 open=50291120
  DEBUG: .../IO/Socket/SSL.pm:2582: OK free ctx 50291120
(6) 关闭证书验证+延迟握手测试

关闭证书验证同时使用延迟握手逻辑,返回相同错误,测试代码如下:

my $sock
= IO::Socket::SSL->new
(
    PeerAddr            => $auth
  , PeerPort            => 'https'
  , SSL_startHandshake  => 0
  , SSL_verify_mode     => 0
)
or die "SSL: $SSL_ERROR";

$sock->connect_SSL
or die "Connect: $SSL_ERROR";

对应调试日志:

DB<1>
  DEBUG: .../IO/Socket/SSL.pm:2537: new ctx 42963376
  DEBUG: .../IO/Socket/SSL.pm:529: socket not yet connected
  DEBUG: .../IO/Socket/SSL.pm:531: socket connected
  BRCC::FM::Test::(bin/socket-check:51):
  51:             $sock->connect_SSL
  52:             or die "Connect: $SSL_ERROR";
    DB<1>
    DEBUG: .../IO/Socket/SSL.pm:553: ssl handshake not started
    DEBUG: .../IO/Socket/SSL.pm:586: using SNI with hostname foo.bar.net
    DEBUG: .../IO/Socket/SSL.pm:653: Net::SSLeay::connect -> -1
    DEBUG: .../IO/Socket/SSL.pm:1769: SSL connect attempt failed

    DEBUG: .../IO/Socket/SSL.pm:1774: SSL connect attempt failed error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
    DEBUG: .../IO/Socket/SSL.pm:659: fatal SSL error: SSL connect attempt failed error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
    DEBUG: .../IO/Socket/SSL.pm:2570: free ctx 42963376 open=42963376
    DEBUG: .../IO/Socket/SSL.pm:2582: OK free ctx 42963376

内容的提问来源于stack exchange,提问作者lembark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 06:06:40