SSL 서버 인증서의 유효성을 검사하기 위해 LWP를 얻으려면 어떻게 해야 합니까?

StackOverflow https://stackoverflow.com/questions/74358

  •  09-06-2019
  •  | 
  •  

문제

어떻게 얻을 수 있나요? LWP 연결하려는 서버의 인증서가 신뢰할 수 있는 기관의 서명을 받았고 올바른 호스트에 발급되었는지 확인하려면 어떻게 해야 합니까?내가 아는 한, 인증서가 내가 연결하는 호스트 이름에 대한 것이라고 주장하는지조차 확인하지 않습니다.이는 주요 보안 허점인 것 같습니다(특히 최근 DNS 취약점의 경우).

업데이트: 알고보니 내가 정말 원했던 건 HTTPS_CA_DIR, ca-bundle.crt가 없기 때문입니다.하지만 HTTPS_CA_DIR=/usr/share/ca-certificates/ 트릭을했습니다.어쨌든 답변이 충분히 가까웠기 때문에 승인된 것으로 표시하고 있습니다.

업데이트 2: 그것은 밝혀졌다 HTTPS_CA_DIR 그리고 HTTPS_CA_FILE Net::SSL을 기본 SSL 라이브러리로 사용하는 경우에만 적용됩니다.그러나 LWP는 IO::Socket::SSL과도 작동합니다. 이는 해당 환경 변수를 무시하고 어떤 인증서가 제공되는지에 관계없이 모든 서버와 원활하게 통신합니다.더 일반적인 해결책이 있습니까?

업데이트 3: 불행히도 솔루션은 아직 완전하지 않습니다.Net::SSL이나 IO::Socket::SSL은 인증서와 비교하여 호스트 이름을 확인하지 않습니다.이는 누군가가 일부 도메인에 대한 합법적인 인증서를 얻은 다음 LWP 불만 없이 다른 도메인을 가장할 수 있음을 의미합니다.

업데이트 4: LWP 6.00 마침내 문제를 해결합니다.보다 내 대답 자세한 내용은.

도움이 되었습니까?

해결책

이 오랜 보안 허점은 마침내 버전 6.00에서 수정되었습니다. libwww-perl.해당 버전부터 기본적으로 LWP::사용자 에이전트 HTTPS 서버가 예상 호스트 이름과 일치하는 유효한 인증서를 제공하는지 확인합니다. $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} false 값으로 설정되거나 해당 변수가 전혀 설정되지 않은 경우 이전 버전과의 호환성을 위해 다음 중 하나를 수행합니다. $ENV{HTTPS_CA_FILE} 또는 $ENV{HTTPS_CA_DIR} 설정됨).

이는 새로운 장치로 제어할 수 있습니다. SSL_opts LWP::UserAgent의 옵션입니다.인증 기관 인증서를 찾는 방법에 대한 자세한 내용은 해당 링크를 참조하세요.하지만 조심하세요, LWP::UserAgent가 작동하던 방식으로, ssl_opts 생성자에 해시한 다음 verify_hostname 기본값은 0 1 대신.(이 버그 LWP 6.03에서 수정되었습니다.) 안전을 위해 항상 다음을 지정하십시오. verify_hostname => 1 당신의 ssl_opts.

그래서 use LWP::UserAgent 6; 서버 인증서의 유효성을 검사하기에 충분해야 합니다.

다른 팁

설치한 SSL 모듈에 따라 이를 수행하는 방법에는 두 가지가 있습니다.그만큼 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에서 디버그* 기호를 가져오는 경우 여러 번의 디버깅도 수행):


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

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를 사용하여 페이지에서 테스트했는데 작동했습니다.핵심은 verify_hostname = 0과 함께 Net::SSL을 사용하는 것입니다.

LWP::UserAgent를 직접(LWP::Simple을 통하지 않고) 사용하는 경우 HTTP::Request 객체에 "If-SSL-Cert-Subject" 헤더를 추가하여 인증서의 호스트 이름을 확인할 수 있습니다.헤더의 값은 인증서 주체에 적용되는 정규식으로 처리되며, 일치하지 않을 경우 요청이 실패합니다.예를 들어:

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

여기에 제시된 모든 솔루션에는 인증서 신뢰 체인의 유효성만 확인하고 인증서의 일반 이름을 연결 중인 호스트 이름과 비교하지 않는다는 점에서 주요 보안 결함이 포함되어 있습니다.따라서 중간에 있는 사람이 임의의 인증서를 제시할 수 있으며 LWP는 신뢰할 수 있는 CA에서 서명한 인증서를 기꺼이 받아들입니다.가짜 인증서의 일반 이름은 LWP에서 확인되지 않으므로 관련이 없습니다.

당신이 사용하는 경우 IO::Socket::SSL LWP의 백엔드로 다음을 설정하여 일반 이름 확인을 활성화할 수 있습니다. 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"
    );
}

Net::SSLGlue( http://search.cpan.org/dist/Net-SSLGlue/lib/Net/SSLGlue.pm ) 그러나 최신 IO::Socket::SSL 및 Net::SSLeay 버전에 따라 다르므로 주의하세요.

당신이 이것에 대해 걱정하는 것이 옳습니다.불행하게도 Perl에서 살펴본 낮은 수준의 SSL/TLS 바인딩에서는 100% 안전하게 수행하는 것이 가능하지 않다고 생각합니다.

기본적으로 핸드쉐이킹이 진행되기 전에 SSL 라이브러리에 연결하려는 서버의 호스트 이름을 전달해야 합니다.또는 적절한 순간에 콜백이 발생하도록 준비하고 체크아웃되지 않으면 콜백 내부에서 핸드셰이크를 중단할 수 있습니다.OpenSSL에 Perl 바인딩을 작성하는 사람들은 콜백 인터페이스를 일관되게 만드는 데 어려움을 겪는 것 같았습니다.

서버 인증서와 호스트 이름을 확인하는 방법도 프로토콜에 따라 다릅니다.따라서 그것은 완벽한 기능에 대한 매개변수가 되어야 합니다.

Netscape/Mozilla NSS 라이브러리에 대한 바인딩이 있는지 확인하고 싶을 수도 있습니다.제가 봤을 땐 이 일을 꽤 잘하는 것 같았어요.

터미널에서 다음 명령을 실행하십시오.sudo cpan 설치 Mozilla::CA

그것은 그것을 해결해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top