it-swarm-eu.dev

Jak mohu získat LWP pro ověření certifikátů SSL serveru?

Jak mohu získat LWP k ověření, zda je certifikát serveru, ke kterému se připojuji, podepsán důvěryhodnou autoritou a vydán správnému hostiteli? Pokud mohu říci, není ani kontrolovat, zda certifikát prohlašuje, že je pro hostname, ke kterému se připojuji. Vypadá to jako hlavní bezpečnostní díra (zejména s nedávnými zranitelnostmi DNS).

Update: Ukazuje se, co jsem opravdu chtěl, bylo HTTPS_CA_DIR, protože nemám ca-bundle.crt. Ale HTTPS_CA_DIR=/usr/share/ca-certificates/ udělal ten trik. Stejně jsem označil odpověď, protože to bylo dost blízko.

Aktualizace 2: Ukazuje se, že HTTPS_CA_DIR a HTTPS_CA_FILE platí pouze v případě, že používáte Net :: SSL jako základní knihovnu SSL. LWP ale také pracuje s IO :: Socket :: SSL, který tyto proměnné prostředí ignoruje a šťastně se s každým serverem hovoří, bez ohledu na to, jaký certifikát prezentuje. Existuje obecnější řešení?

Aktualizace 3: Bohužel řešení stále není úplné. Net :: SSL ani IO :: Socket :: SSL kontroluje název hostitele proti certifikátu. To znamená, že někdo může získat legitimní certifikát pro určitou doménu a poté se vydávat za jinou doménu, aniž by si stěžoval LWP.

Update 4: _ ​​ LWP 6.00 konečně vyřeší problém. Podrobnosti viz moje odpověď .

44
cjm

Tato dlouhodobá bezpečnostní díra byla konečně opravena ve verzi 6.00 libwww-Perl . Počínaje touto verzí standardně LWP :: UserAgent ověří, že servery HTTPS představují platný certifikát odpovídající očekávanému názvu hostitele (pokud není $ENV{Perl_LWP_SSL_VERIFY_HOSTNAME} nastaveno na hodnotu false nebo pro zpětnou kompatibilitu, pokud tato proměnná není nastavena vůbec, buď $ENV{HTTPS_CA_FILE} nebo $ENV{HTTPS_CA_DIR} je nastaveno).

To může být řízeno novou ssl_opts možností LWP :: UserAgent. Podrobnosti o tom, jak se nacházejí certifikáty certifikační autority, naleznete v tomto odkazu. Ale buďte opatrní, způsob, jakým LWP :: UserAgent pracoval, pokud poskytnete konstruktoru ssl_opts hash, pak verify_hostname výchozí hodnota 0 namísto 1. ( Tato chyba byla opravena v LWP 6.03.) Chcete-li být v bezpečí, vždy zadejte verify_hostname => 1 ve vašem ssl_opts.

use LWP::UserAgent 6; by tedy mělo být dostatečné k ověření platnosti certifikátů serveru.

37
cjm

Existují dva způsoby, jak toho dosáhnout, v závislosti na nainstalovaném modulu SSL. Dokumenty LWP doporučují instalaci Crypt :: SSLeay . Pokud je to to, co jste udělali, nastavení proměnné prostředí HTTPS_CA_FILE tak, aby ukazovalo na váš soubor ca-bundle.crt, by mělo dělat trik. ( Crypt :: SSLeay docs zmiňuje to, ale je to trochu světlo na detaily). V závislosti na nastavení může být nutné místo toho nastavit proměnnou prostředí HTTPS_CA_DIR.

Příklad pro 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

Všimněte si, že nezískáme die, ale vrátí undef.

Alternativně můžete použít modul IO::Socket::SSL (také dostupný z CPAN). Chcete-li tento certifikát ověřit, musíte změnit výchozí nastavení kontextu 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");

Tato verze také způsobí, že get() vrátí undef, ale vytiskne varování STDERR, když ho spustíte (stejně jako spoustu ladění, pokud importujete symboly ladění * z IO :: Socket :: SSL):


% 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) 
9
Brian Phillips

Přistál jsem na této stránce hledající způsob, jak obejít SSL validaci, ale všechny odpovědi byly stále velmi užitečné. Tady jsou moje nálezy. Pro ty, kteří chtějí vynechat validaci SSL (nedoporučuje se, ale mohou existovat případy, kdy budete muset absolutně), jsem na lwp 6.05 a to fungovalo pro mě:

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

Také jsem testoval na stránce s POST a pracoval také. Klíčem je použít Net :: SSL spolu s jménem authentication_hostname = 0.

6
bshok

Všechna zde uvedená řešení obsahují hlavní bezpečnostní chybu, protože pouze ověřují platnost důvěryhodného řetězce certifikátu, ale neporovnávají společné jméno certifikátu s hostitelským jménem, ​​ke kterému se připojujete. Muž uprostřed vás tedy může předložit libovolný certifikát a LWP to s radostí přijme, pokud je podepsán certifikační autoritou, které důvěřujete. Obecný název falešného certifikátu je irelevantní, protože jej LWP nikdy nekontroluje.

Pokud používáte IO::Socket::SSL jako backend LWP, můžete povolit ověření společného názvu nastavením parametru verifycn_scheme, jako je tento:

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

Pokud používáte LWP :: UserAgent přímo (ne přes LWP :: Simple), můžete ověřit název hostitele v certifikátu přidáním záhlaví "If-SSL-Cert-Subject" do objektu HTTP :: Request. Hodnota záhlaví je považována za regulární výraz, který má být aplikován na předmět certifikátu, a pokud neodpovídá, požadavek se nezdaří. Například:

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

bude tisknout

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

Máte pravdu, abyste se o to obávali. Bohužel si nemyslím, že je možné to udělat 100% bezpečně pod některou z nízkoúrovňových SSL/TLS vazeb, na které jsem se díval.

Před tím, než se handshaking rozběhne, musíte v podstatě předat název hostitele serveru, ke kterému se chcete připojit k knihovně SSL. Případně můžete uspořádat zpětné volání, které se uskuteční ve správný okamžik, a zrušte handshake zevnitř zpětného volání, pokud se nevyzkouší. Zdálo se, že lidé psající vazby Perlu na OpenSSL mají problémy s důsledným vytvářením rozhraní pro zpětné volání.

Metoda kontroly názvu hostitele proti certifikátu serveru je také závislá na protokolu. Takže by to musel být parametr jakékoli dokonalé funkce.

Možná budete chtít zjistit, zda existují nějaké vazby na knihovnu Netscape/Mozilla NSS. Zdálo se mi to docela dobře, když jsem se na to podíval.

1
Marsh Ray

Můžete také zvážit Net :: SSLGlue ( http://search.cpan.org/dist/Net-SSLGlue/lib/Net/SSLGlue.pm ) Ale pozor, záleží na nedávné IO :: Socket :: SSL a Net :: SSLeay verze.

1
goneri

Proveďte následující příkaz v terminálu: Sudo cpan install Mozilla :: CA

Mělo by to vyřešit.

0
Bojoer