49 votes

Comment faire en sorte que LWP valide les certificats de serveur SSL?

Comment puis-je obtenir LWP pour vérifier que le certificat du serveur, je me connecte à est signé par une autorité de confiance et délivré à l'accueil correct? Aussi loin que je peux dire, il n'a même pas vérifier que le certificat prétend être le nom d'hôte que je suis connecté. Ça semble être un trou de sécurité majeur (surtout avec la récente DNS de vulnérabilités).

Mise à jour: Il s'avère que je voulais, c'était HTTPS_CA_DIR, parce que je n'ai pas de ca-bundle.crt. Mais HTTPS_CA_DIR=/usr/share/ca-certificates/ a fait le tour. Je suis marquant la réponse que accepté de toute façon, parce que c'était assez proche.

Mise à jour 2: Il s'avère que HTTPS_CA_DIR et HTTPS_CA_FILE ne s'applique que si vous utilisez Net::SSL sous-jacents de la bibliothèque SSL. Mais LWP travaille également avec IO::Socket::SSL, qui ignore les variables d'environnement et heureux de parler à n'importe quel serveur, n'importe quel certificat qu'il présente. Est-il plus général de la solution?

Mise à jour 3: Malheureusement, la solution n'est pas encore terminée. Ni Net::SSL ni IO::Socket::SSL est en train de vérifier le nom de l'hôte contre le certificat. Cela signifie que quelqu'un peut obtenir une légitime certificat pour certains domaine, et alors l'identité de n'importe quel autre domaine sans LWP se plaindre.

Mise à jour 4: LWP 6.00 résout enfin le problème. Voir ma réponse pour plus de détails.

41voto

cjm Points 44090

Cette faille de sécurité a enfin été corrigé dans la version 6.00 de libwww-perl. À partir de cette version, par défaut de LWP::UserAgent vérifie que les serveurs HTTPS présenter un certificat valide correspondant à l'devraient nom d'hôte (à moins d' $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} est définie sur la valeur false ou, pour la compatibilité ascendante si cette variable n'est pas définie, soit $ENV{HTTPS_CA_FILE} ou $ENV{HTTPS_CA_DIR} est réglé).

Cela peut être contrôlée par le nouveau ssl_opts option de LWP::UserAgent. Voir ce lien pour plus de détails sur la façon dont le Certificat les certificats d'Autorité sont situés. Mais attention, le chemin de LWP::UserAgent l'habitude de travailler, si vous fournissez un ssl_opts de hachage pour le constructeur, alors verify_hostname par défaut à 0 au lieu de 1. (Ce bug a été corrigé dans LWP 6.03.) Pour être sûr, toujours spécifier verify_hostname => 1 votre ssl_opts.

Donc, use LWP::UserAgent 6; devrait être suffisant pour avoir des certificats de serveur de validation.

9voto

Brian Phillips Points 7023

Il y a deux moyens de le faire selon laquelle le protocole SSL module que vous avez installés. La LWP docs vous recommandons d'installer Crypt::SSLeay. Si c'est ce que vous avez fait, le réglage du HTTPS_CA_FILE variable d'environnement pour pointer vers votre ca-bundle.le crt devrait faire l'affaire. (la Crypte::SSLeay docs en parle, mais c'est un peu la lumière sur les détails). Aussi, selon votre configuration, vous devrez peut-être définir l' HTTPS_CA_DIR variable d'environnement à la place.

Exemple pour 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

Notez que get ne die, mais retourne une undef.

Alternativement, vous pouvez utiliser l' IO::Socket::SSL module (également disponible sur le CPAN). Pour faire de cet vérifier le certificat du serveur, vous devez modifier le SSL contexte par défaut:


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

Cette version est aussi provoque get() de retour du fnud, mais affiche un message d'avertissement à l' STDERR lorsque vous l'exécuter (en tant que bien comme un tas de débogage si vous importez le debug* symboles de 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) 

7voto

bshok Points 1

J'ai atterri sur cette page à la recherche d'un moyen de contourner la validation SSL, mais toutes les réponses ont été très utiles. Voici mes conclusions. Pour ceux qui cherchent à contourner la validation SSL (non recommandé mais il peut arriver que vous deviez absolument le faire), je suis sur lwp 6.05 et cela a fonctionné pour moi:

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

J'ai également testé sur une page avec POST et cela a également fonctionné. La clé consiste à utiliser Net :: SSL avec verify_hostname = 0.

2voto

dave0 Points 11

Si vous utilisez directement LWP :: UserAgent (et non via LWP :: Simple), vous pouvez valider le nom d'hôte dans le certificat en ajoutant l'en-tête "If-SSL-Cert-Subject" à votre objet HTTP :: Request. La valeur de l'en-tête est traitée comme une expression régulière à appliquer sur le sujet du certificat. Si elle ne correspond pas, la demande échoue. Par exemple:

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

imprimera

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

1voto

goneri Points 41

Vous pouvez également envisager Net :: SSLGlue ( http://search.cpan.org/dist/Net-SSLGlue/lib/Net/SSLGlue.pm ). Mais attention, cela dépend de la récente IO :: Socket :: SSL et Net :: versions SSLeay.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X