Frage

Wie kann ich LWP zu überprüfen, ob das Zertifikat des Servers Ich verbinde um durch eine vertrauenswürdige Autorität und erteilt an den richtigen Host unterzeichnet? Soweit ich sagen kann, ist es nicht einmal prüfen, ob das Zertifikat für die Hostnamen sein behauptet, ich bin zu verbinden. Das scheint wie ein großes Sicherheitsloch (vor allem mit den jüngsten DNS-Schwachstellen).

Update: Es stellt sich heraus, was ich wirklich wollte, war HTTPS_CA_DIR, weil ich kein ca-bundle.crt haben. Aber HTTPS_CA_DIR=/usr/share/ca-certificates/ hat den Trick. Ich Kennzeichnung die Antwort als ohnehin angenommen, weil es nahe genug war.

Update 2: Es stellt sich heraus, dass HTTPS_CA_DIR und HTTPS_CA_FILE gelten nur, wenn Sie mit Net :: SSL als die zugrunde liegende SSL-Bibliothek. Aber LWP arbeitet auch mit IO :: Socket :: SSL, die diese Umgebungsvariablen ignoriert und glücklich zu jedem Server sprechen, egal, was es Zertifikat präsentiert. Gibt es eine allgemeine Lösung?

Update 3: Leider noch die Lösung nicht vollständig ist. Weder Net :: SSL noch IO :: Socket :: SSL wird der Hostname gegen das Zertifikat zu überprüfen. Dies bedeutet, dass jemand ein berechtigtes Zertifikat für einige Domain bekommen, und dann imitiert andere Domain ohne LWP beschweren.

Update 4: LWP 6,00 schließlich löst das Problem. Siehe meine Antwort .

War es hilfreich?

Lösung

Diese langjährige Sicherheitslücke ist in Version 6.00 von libwww-perl . Beginnend mit dieser Version standardmäßig LWP :: Useragent überprüft, dass HTTPS-Server ein gültiges Zertifikat vorlegen die erwarteten Hostnamen stehen (es sei denn $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} für Rückwärtskompatibilität zu einem falschen Wert oder wird gesetzt, wenn die variablen nicht gesetzt ist, entweder $ENV{HTTPS_CA_FILE} oder $ENV{HTTPS_CA_DIR} gesetzt ist).

Dies kann durch die neuen ssl_opts Option von LWP :: Useragent . Siehe diesen Link für Details, wie die Zertifizierungsstelle Zertifikate befinden. Aber vorsichtig , die Art und Weise LWP :: Useragent verwendet wird, arbeiten, wenn Sie einen ssl_opts Hash an den Konstruktor bereitstellen, dann verify_hostname voreingestellt auf 0 anstelle von 1. ( Dieser Fehler in LWP 6,03 festgelegt wurde.) Um sicher zu sein, immer angeben verify_hostname => 1 in Ihrem ssl_opts.

So use LWP::UserAgent 6; sollte ausreichend sein, Serverzertifikate für gültig erklärt werden.

Andere Tipps

Es gibt zwei Möglichkeiten, dies zu tun, je nachdem, welches SSL-Modul, das Sie installiert haben. Die LWP docs empfehlen die Installation Crypt :: SSLeay . Wenn das, was du getan hast, die HTTPS_CA_FILE Umgebungsvariable auf Ihre ca-bundle.crt Punkt sollte es tun. (Die Crypt :: SSLeay docs dies erwähnt, ist aber ein wenig Licht auf Details) . Auch abhängig von Ihrem Setup, müssen Sie möglicherweise die HTTPS_CA_DIR Umgebungsvariable statt setzen.

Beispiel für 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

Beachten Sie, dass nicht die bekommen, aber es hat eine undef zurück.

Alternativ können Sie das IO::Socket::SSL Modul (auch aus dem CPAN) verwenden. Hierzu wird das Server-Zertifikat benötigen Sie machen überprüfen Sie die SSL-Kontext Standardwerte zu ändern:


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");

Diese Version führt auch get() undef zurück, sondern gibt eine Warnung an STDERR, wenn Sie es ausführen (wie auch eine Reihe von Debugging, wenn Sie die Debug-* Symbole von IO :: Socket :: SSL importieren):


% 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) 

ich auf dieser Seite gelandet nach einer Möglichkeit, SSL-Validierung zu umgehen, aber alle Antworten waren immer noch sehr hilfreich. Hier sind meine Ergebnisse. Für diejenigen, die SSL-Validierung (nicht empfohlen, aber es kann Fälle geben, in denen Sie unbedingt müssen) umgehen, ich bin auf lwp 6,05 und dies war für mich:

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";
}

ich auch auf einer Seite mit POST getestet und es funktionierte auch. Der Schlüssel ist, Net :: Verwendung von SSL zusammen mit verify_hostname = 0 ist.

Wenn Sie LWP :: Useragenten verwenden, um direkt (nicht über LWP :: Simple) Sie die Hostnamen im Zertifikat validieren können durch Zugabe des "If-SSL-Cert-Betreff" Header HTTP :: Request-Objekt. Der Wert des Header wird als regulärer Ausdruck behandelt auf dem Zertifikat angewendet werden, und wenn dies nicht der Fall, schlägt die Anforderung fehl. Zum Beispiel:

#!/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"

druckt

Status: 500 Bad SSL certificate subject: '/C=CA/ST=Ontario/L=Ottawa/O=Your Org/CN=yourdomain.tld' !~ //CN=make-it-fail.tld/

Alle vorgestellten Lösungen hier enthalten eine große Sicherheitslücke, indem sie nur die Gültigkeit der Vertrauenskette des Zertifikats überprüfen, aber das Zertifikat des Common Name mit dem Hostnamen Sie eine Verbindung nicht vergleichen. So kann ein Mann in der Mitte ein beliebiges Zertifikat präsentieren Sie und LWP es glücklich, so lange akzeptieren, wie es von einer Zertifizierungsstelle signiert ist, die Sie vertrauen. Die gefälschte Zertifikat des Common Name ist irrelevant, weil es nie von LWP.

überprüft hat

Wenn Sie IO::Socket::SSL als LWP Backend verwenden, können Sie die Überprüfung des Common Namen aktivieren, indem Sie die verifycn_scheme Parameter wie diese Einstellung:

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"
    );
}

Sie können auch prüfen, Net :: SSLGlue ( http: //search.cpan.org/dist/Net-SSLGlue/lib/Net/SSLGlue.pm ) Aber kümmern, hängt es von den letzten IO :: Socket :: SSL und Net :: SSLeay Versionen.

Sie haben Recht darüber besorgt zu sein. Leider glaube ich nicht ist es möglich, es zu 100% sicher unter einem des Low-Level-SSL / TLS-Bindungen mich für Perl sah zu tun.

Im Wesentlichen müssen Sie in den Host-Namen des Servers, den Sie auf die SSL-Bibliothek verbinden möchten passieren, bevor das Handshaking in Gang kommt. Alternativ können Sie arrangieren für einen Rückruf im richtigen Moment treten und das Handshake aus dem Innern des Rückruf abbrechen, wenn es nicht aus, überprüft. Menschen Perl-Bindungen zu OpenSSL schreiben schien Probleme zu haben, die Callback-Schnittstelle machen konsequent.

Die Methode den Hostnamen an den Server des cert zu überprüfen, ist auf dem Protokoll abhängig, auch. Also das wäre ein Parameter auf jede perfekte Funktion sein.

Sie können sehen wollen, ob es irgendwelche Bindungen an die Netscape / Mozilla NSS-Bibliothek sind. Es schien ziemlich gut dies zu tun, als ich es sah.

Führen Sie einfach den folgenden Befehl im Terminal ausführen: sudo cpan installieren Mozilla :: CA

Es sollte es lösen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top