【问题标题】:Perl: Cannot Access Web Service with SSLPerl:无法使用 SSL 访问 Web 服务
【发布时间】:2017-06-08 22:05:39
【问题描述】:

这是我的第一个 Perl 脚本。我已经使用 CPAN 安装了 SOAP::Lite,似乎一切正常。

我正在尝试访问一个简单的 HelloWorld .NET Web 服务。我收到一个似乎与 Perl 或 SOAP::Lite 无法验证 SSL 证书有关的错误。

虽然看起来返回的是 500 的代码,但我创建了一个 Java 客户端,它能够很好地调用 Web 方法,所以我认为问题不在 Web 服务端。

谁能给我指出正确的方向,让我如何让它发挥作用?

脚本:

#!/usr/bin/perl

use SOAP::Lite 'trace', 'debug';

$api_ns = "https://www.mydomain.com/edgedev/";
$api_url = "https://www.mydomain.com/edgedev/ws.asmx";
$action = "HelloWorld";

my $soap = SOAP::Lite
                -> readable(1)
                -> ns($api_ns, 'tns')
                -> proxy($api_url)
                -> on_action(sub { return "\"$action\""});

print $soap->HelloWorld()->result;

结果

<soap:Envelope 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
    xmlns:tns="https://www.mydomain.com/edgedev/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <tns:HelloWorld xsi:nil="true" />
      </soap:Body>
</soap:Envelope>
SOAP::Transport::HTTP::Client::send_receive: 500 Can't connect to www.mydomain.com:443 (certificate verify failed)
Content-Type: text/plain
Client-Date: Tue, 12 Feb 2013 16:40:28 GMT
Client-Warning: Internal response

Can't connect to www.mydomain.com:443 (certificate verify failed)

You can disable hostname check by setting environment variable PERL_LWP_SSL_VERIFY_HOSTNAME=0

LWP::Protocol::https::Socket: SSL connect attempt failed with unknown errorerror:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed at /usr/lib/perl5/vendor_perl/5.10.0/LWP/Protocol/http.pm line 57.
500 Can't connect to www.mydomain.com:443 (certificate verify failed) at ./soaptest.pl line 15

【问题讨论】:

    标签: perl cpan soaplite


    【解决方案1】:

    这里是如何使这项工作安全地工作,即不禁用 SSL 主机名检查。

    如果您使用 CA 签名证书与公共系统通信,则需要将 LWP 指向您的发行版的根证书集合。在基于 Debian 的系统(Ubuntu 等)下,它保存在 /etc/ssl/certs/ 下。

    BEGIN {
        $ENV{HTTPS_CA_DIR} = '/etc/ssl/certs'
    }
    

    如果您使用自签名证书与自己的服务器通信,则可以在客户端上保存该证书的副本,并将脚本指向该特定文件。

    BEGIN {
        $ENV{HTTPS_CA_FILE} = '/path/to/my/server-certificate.crt'
    }
    

    您可以在运行脚本之前在环境中设置这些(例如,从您的 shell 中导出它们),或者您可以将设置直接应用到您的 UserAgent 对象。有关详细信息,请参阅LWP::UserAgent documentation;搜索ssl_opts

    【讨论】:

      【解决方案2】:

      $soap-&gt;{_transport}-&gt;{_proxy}-&gt;{ssl_opts}-&gt;{verify_hostname} = 0;

      【讨论】:

      • $soap-&gt;ssl_opts( verify_hostname =&gt; 0 ); 电话对我不起作用,但上面的电话起作用了。所以在这里 +1。
      【解决方案3】:

      刚刚找到这个帖子,一切都对我很有用,谢谢!

      我想添加我的“解决方案”,这是对之前的一个变体,以防它帮助其他人。

      添加

      $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
      

      绝对是关键。但是,这会导致IO::Socket::SLL 发出警告:

      *******************************************************************
       Using the default of SSL_verify_mode of SSL_VERIFY_NONE for client
       is deprecated! Please set SSL_verify_mode to SSL_VERIFY_PEER
       together with SSL_ca_file|SSL_ca_path for verification.
       If you really don't want to verify the certificate and keep the
       connection open to Man-In-The-Middle attacks please set
       SSL_verify_mode explicitly to SSL_VERIFY_NONE in your application.
      *******************************************************************
      

      消除该警告的方法是添加以下行:

      use IO::Socket::SSL;
      IO::Socket::SSL::set_defaults(SSL_verify_mode => "SSL_VERIFY_NONE");
      

      除了原始的$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME},无论您使用什么客户端(LWP::UserAgentRPC::XML::ClientSOAP::Lite 等),它都应该可以工作。

      希望对其他人有所帮助!

      【讨论】:

        【解决方案4】:

        您需要告诉 LWP 不要进行主机名检查。对我来说,这只适用于环境变量,而不是通过在 SOAP::Lite 对象中设置选项:

        $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;
        

        【讨论】:

          【解决方案5】:

          在 perl v5.20.2 中,我需要两件事来禁用 ssl 证书验证:

          在创建任何 SOAP 对象之前(我已将其放在顶部)

          $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
          

          然后修改SOAP代理:

          my $soap = SOAP::Lite
                      -> readable(1)
                      -> ns($api_ns, 'tns')
                      -> proxy($api_url, ssl_opts => [ SSL_verify_mode => 0 ] )
                      -> on_action(sub { return "\"$action\""});
          

          【讨论】:

            【解决方案6】:

            由于 SOAP::Lite 重复 LWP 调用,因此应该可以使用

            $soap->ssl_opts( verify_hostname => 0 );
            

            【讨论】:

              【解决方案7】:

              或者在调用 SOAP 方法之前添加你的代码:

              $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
              

              【讨论】:

                【解决方案8】:

                男孩为我做了这项工作! 我把它扔进了 stubmaker.pl 和我的使用 stubmaker.pl 输出的脚本。

                IO::Socket::SSL::set_defaults(SSL_verify_mode => "SSL_VERIFY_NONE");
                use SOAP::Lite +trace => qw( debug );
                
                $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0; 
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-02-16
                  • 1970-01-01
                  • 2018-12-10
                  • 2016-09-20
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多