48

接続しているサーバーの証明書が信頼できる機関によって署名され、正しいホストに発行されていることをLWPで確認するにはどうすればよいですか? 私が知る限り、証明書が接続先のホスト名のものであると主張していることさえチェックしません。これは重大なセキュリティ ホールのように思えます (特に最近の DNS の脆弱性では)。

更新:HTTPS_CA_DIR ca-bundle.crt を持っていないので、私 が本当に欲しかったのは であることがわかりました。しかしHTTPS_CA_DIR=/usr/share/ca-certificates/、トリックをしました。とにかく、答えは十分に近かったので、受け入れられたものとしてマークしています。

更新 2:基盤となる SSL ライブラリとして Net::SSL を使用している場合HTTPS_CA_DIRにのみ適用されることが判明しました。HTTPS_CA_FILEしかし、LWP は IO::Socket::SSL でも動作します。IO::Socket::SSL は、これらの環境変数を無視し、提示する証明書に関係なく、任意のサーバーと問題なく通信します。より一般的な解決策はありますか?

更新 3:残念ながら、解決策はまだ完全ではありません。Net::SSL も IO::Socket::SSL も証明書に対してホスト名をチェックしていません。これは、あるドメインの正当な証明書を誰かが取得し、LWP が文句を言うことなく他のドメインになりすますことができることを意味します。

アップデート 4: LWP 6.00がついにこの問題を解決しました。詳細については、私の回答を参照してください。

4

8 に答える 8

40

この長年にわたるセキュリティ ホールは、libwww-perlのバージョン 6.00 で最終的に修正されました。そのバージョン以降、デフォルトで、LWP::UserAgentは、HTTPS サーバーが期待されるホスト名に一致する有効な証明書を提示することを検証します ( $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}false 値に設定されていないか、下位互換性のためにその変数がまったく設定されていない場合、$ENV{HTTPS_CA_FILE}または設定されている場合を除く$ENV{HTTPS_CA_DIR}) 。 .

これは、LWP::UserAgentの新しいssl_optsオプションによって制御できます。認証局証明書の場所の詳細については、そのリンクを参照してください。ただし、LWP::UserAgent の以前の動作方法では、コンストラクターにハッシュを指定すると、デフォルトで 1 ではなく 0になります(このバグは LWP 6.03 で修正されました) 。ssl_optsverify_hostnameverify_hostname => 1ssl_opts

したがってuse LWP::UserAgent 6;、サーバー証明書を検証するのに十分なはずです。

于 2011-03-16T17:20:31.593 に答える
9

インストールしたSSLモジュールに応じて、これを行うには2つの方法があります。LWPドキュメントでは、Crypt::SSLeayをインストールすることを推奨しています。それがあなたがやったことならHTTPS_CA_FILE、ca-bundle.crtを指すように環境変数を設定することでうまくいくはずです。(Crypt :: SSLeayのドキュメントにはこれが記載されていますが、詳細については少し説明があります)。HTTPS_CA_DIRまた、設定によっては、代わりに環境変数を設定する必要がある場合があります。

Crypt :: SSLeayの例:


use LWP::Simple qw(get);
$ENV{HTTPS_CA_FILE} = "/path/to/your/ca/file/ca-bundle";
$ENV{HTTPS_DEBUG} = 1;

print get("https://some-server-with-bad-certificate.com");

__END__
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
SSL3 alert write:fatal:unknown CA
SSL_connect:error in SSLv3 read server certificate B
SSL_connect:error in SSLv3 read server certificate B
SSL_connect:before/connect initialization
SSL_connect:SSLv3 write client hello A
SSL_connect:SSLv3 read server hello A
SSL3 alert write:fatal:bad certificate
SSL_connect:error in SSLv3 read server certificate B
SSL_connect:before/connect initialization
SSL_connect:SSLv2 write client hello A
SSL_connect:error in SSLv2 read server hello B

getはそうではないdieが、を返すことに注意してくださいundef

または、モジュールを使用することIO::Socket::SSLもできます(CPANからも入手できます)。これでサーバー証明書を確認するには、SSLコンテキストのデフォルトを変更する必要があります。


use IO::Socket::SSL qw(debug3);
use Net::SSLeay;
BEGIN {
    IO::Socket::SSL::set_ctx_defaults(
        verify_mode => Net::SSLeay->VERIFY_PEER(),
        ca_file => "/path/to/ca-bundle.crt",
      # ca_path => "/alternate/path/to/cert/authority/directory"
    );
}
use LWP::Simple qw(get);

warn get("https:://some-server-with-bad-certificate.com");

このバージョンでもget()undefが返されますが、STDERR実行時に警告が出力されます(IO :: Socket ::SSLからdebug*シンボルをインポートする場合は一連のデバッグも同様です)。


% perl ssl_test.pl
DEBUG: .../IO/Socket/SSL.pm:1387: new ctx 139403496
DEBUG: .../IO/Socket/SSL.pm:269: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:271: socket connected
DEBUG: .../IO/Socket/SSL.pm:284: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:327: Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:1135: SSL connect attempt failed with unknown errorerror:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

DEBUG: .../IO/Socket/SSL.pm:333: fatal SSL error: SSL connect attempt failed with unknown errorerror:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:1422: free ctx 139403496 open=139403496
DEBUG: .../IO/Socket/SSL.pm:1425: OK free ctx 139403496
DEBUG: .../IO/Socket/SSL.pm:1135: IO::Socket::INET configuration failederror:00000000:lib(0):func(0):reason(0)
500 Can't connect to some-server-with-bad-certificate.com:443 (SSL connect attempt failed with unknown errorerror:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed) 

于 2008-09-16T16:49:41.060 に答える
7

SSL検証をバイパスする方法を探してこのページにたどり着きましたが、すべての回答は依然として非常に役に立ちました. これが私の発見です。SSL検証をバイパスしようとしている人のために(推奨されませんが、絶対に必要な場合があるかもしれません)、私はlwp 6.05を使用していますが、これはうまくいきました:

use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common qw(GET);
use Net::SSL;

my $ua = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0 }, );
my $req = GET 'https://github.com';
my $res = $ua->request($req);
if ($res->is_success) {
    print $res->content;
} else {
    print $res->status_line . "\n";
}

私も POST を使用してページでテストしましたが、それも機能しました。重要なのは、Net::SSL を verify_hostname = 0 と共に使用することです。

于 2014-05-09T17:32:54.347 に答える
2

ここに示すすべてのソリューションには、証明書の信頼チェーンの有効性を検証するだけで、証明書の共通名を接続先のホスト名と比較しないという大きなセキュリティ上の欠陥が含まれています。したがって、中間者が任意の証明書を提示する可能性があり、信頼できるCAによって署名されている限り、LWPはそれを喜んで受け入れます。偽の証明書の共通名は、LWPによってチェックされることがないため、関係ありません。

IO::Socket::SSLLWPのバックエンドとして使用している場合は、次のverifycn_schemeようにパラメーターを設定することで、共通名の検証を有効にできます。

use IO::Socket::SSL;
use Net::SSLeay;
BEGIN {
    IO::Socket::SSL::set_ctx_defaults(
        verify_mode => Net::SSLeay->VERIFY_PEER(),
        verifycn_scheme => 'http',
        ca_path => "/etc/ssl/certs"
    );
}
于 2011-10-11T06:11:04.287 に答える
2

LWP::UserAgent を (LWP::Simple 経由ではなく) 直接使用する場合、"If-SSL-Cert-Subject" ヘッダーを HTTP::Request オブジェクトに追加することで、証明書のホスト名を検証できます。ヘッダーの値は、証明書のサブジェクトに適用される正規表現として扱われ、一致しない場合、要求は失敗します。例えば:

#!/usr/bin/perl 
use LWP::UserAgent;
my $ua = LWP::UserAgent->new();
my $req = HTTP::Request->new(GET => 'https://yourdomain.tld/whatever');
$req->header('If-SSL-Cert-Subject' => '/CN=make-it-fail.tld');

my $res = $ua->request( $req );

print "Status: " . $res->status_line . "\n"

印刷します

Status: 500 Bad SSL certificate subject: '/C=CA/ST=Ontario/L=Ottawa/O=Your Org/CN=yourdomain.tld' !~ //CN=make-it-fail.tld/
于 2009-03-04T20:16:13.013 に答える
1

Net :: SSLGlue( http://search.cpan.org/dist/Net-SSLGlue/lib/Net/SSLGlue.pm )も検討してください。ただし、最近のIO :: Socket::SSLとNet::SSLeayバージョン。

于 2010-02-23T13:14:28.167 に答える
1

あなたがこれについて心配するのは正しいです。残念ながら、Perl について調べた低レベルの SSL/TLS バインディングのいずれかの下で 100% 安全に行うことは不可能だと思います。

基本的に、ハンドシェイクが開始される前に、SSL ライブラリに接続するサーバーのホスト名を渡す必要があります。または、適切なタイミングでコールバックが発生するように調整し、チェックアウトしない場合はコールバック内からハンドシェイクを中止することもできます。OpenSSL への Perl バインディングを作成している人々は、コールバック インターフェイスを一貫して作成するのに問題があるようです。

サーバーの証明書に対してホスト名を確認する方法も、プロトコルに依存します。したがって、それは完全な関数のパラメーターである必要があります。

Netscape/Mozilla NSS ライブラリへのバインドがあるかどうかを確認したい場合があります。私がそれを見たとき、これを行うのはかなり上手に思えました。

于 2010-02-23T23:47:29.493 に答える
0

ターミナルで次のコマンドを実行するだけです: sudo cpan install Mozilla::CA

それはそれを解決するはずです。

于 2016-02-06T16:07:18.960 に答える