Skip to content

Commit

Permalink
Change verify_SSL default to 1, add ENV var to enable insecure default
Browse files Browse the repository at this point in the history
- Changes the `verify_SSL` default parameter from `0` to `1`

  Based on patch by Dominic Hargreaves:
  https://salsa.debian.org/perl-team/interpreter/perl/-/commit/1490431e40e22052f75a0b3449f1f53cbd27ba92

  Fixes CVE-2023-31486

- Add check for `$ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT}` that
  enables the previous insecure default behaviour if set to `1`.

  This provides a workaround for users who encounter problems with the
  new `verify_SSL` default.

  Example to disable certificate checks:
  ```
    $ PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT=1 ./script.pl
  ```

- Updates to documentation:
  - Describe changing the verify_SSL value
  - Describe the escape-hatch environment variable
  - Remove rationale for not enabling verify_SSL
  - Add missing certificate search paths
  - Replace "SSL" with "TLS/SSL" where appropriate
  - Use "machine-in-the-middle" instead of "man-in-the-middle"

- Update `210_live_ssl.t`
  - Use github.com, cpan.org and badssl.com hosts for checking
    certificates.
  - Add self signed snake-oil certificate for checking failures rather
    than bypassing the `SSL_verify_callback`
  - Test `verify_SSL` parameter in addition to low level SSL_options
  - Test that `PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT=1` behaves as
    expected against badssl.com

- Added `180_verify_SSL.t`
  - Test that `verify_SSL` default is `1`
  - Test that `PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT` behaves as expected
  - Test that using different values for `verify_SSL` and legacy `verify_ssl`
    doesn't disable cert checks
  • Loading branch information
stigtsp committed Jun 10, 2023
1 parent 7bdf71f commit 6cd99f8
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 73 deletions.
72 changes: 43 additions & 29 deletions lib/HTTP/Tiny.pm
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,15 @@ This constructor returns a new HTTP::Tiny object. Valid attributes include:
* C<timeout> — Request timeout in seconds (default is 60) If a socket open,
read or write takes longer than the timeout, the request response status code
will be 599.
* C<verify_SSL> — A boolean that indicates whether to validate the SSL
certificate of an C<https> — connection (default is false)
* C<verify_SSL> — A boolean that indicates whether to validate the TLS/SSL
certificate of an C<https> — connection (default is true). Changed from false
to true in version 0.083.
* C<SSL_options> — A hashref of C<SSL_*> — options to pass through to
L<IO::Socket::SSL>
* C<$ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT}> - Changes the default
certificate verification behavior to not check server identity to if set to 1.
Only effective if C<verify_SSL> is not set. Added in version 0.083.
An accessor/mutator method exists for each attribute.
Expand Down Expand Up @@ -111,11 +116,17 @@ sub timeout {
sub new {
my($class, %args) = @_;

# Support lower case verify_ssl argument, but only if verify_SSL is not
# true.
if ( exists $args{verify_ssl} ) {
$args{verify_SSL} ||= $args{verify_ssl};
}

my $self = {
max_redirect => 5,
timeout => defined $args{timeout} ? $args{timeout} : 60,
keep_alive => 1,
verify_SSL => $args{verify_SSL} || $args{verify_ssl} || 0, # no verification by default
verify_SSL => defined $args{verify_SSL} ? $args{verify_SSL} : _verify_SSL_default(),
no_proxy => $ENV{no_proxy},
};

Expand All @@ -134,6 +145,13 @@ sub new {
return $self;
}

sub _verify_SSL_default {
my ($self) = @_;
# Check if insecure default certificate verification behaviour has been
# changed by the user by setting PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT=1
return (($ENV{PERL_HTTP_TINY_INSECURE_BY_DEFAULT} || '') eq '1') ? 0 : 1;
}

sub _set_proxies {
my ($self) = @_;

Expand Down Expand Up @@ -1060,7 +1078,7 @@ sub new {
timeout => 60,
max_line_size => 16384,
max_header_lines => 64,
verify_SSL => 0,
verify_SSL => HTTP::Tiny::_verify_SSL_default(),
SSL_options => {},
%args
}, $class;
Expand Down Expand Up @@ -1744,52 +1762,43 @@ of L<IO::Socket::INET> for transparent support for both IPv4 and IPv6.
Cookie support requires L<HTTP::CookieJar> or an equivalent class.
=head1 SSL SUPPORT
=head1 TLS/SSL SUPPORT
Direct C<https> connections are supported only if L<IO::Socket::SSL> 1.56 or
greater and L<Net::SSLeay> 1.49 or greater are installed. An error will occur
if new enough versions of these modules are not installed or if the SSL
if new enough versions of these modules are not installed or if the TLS
encryption fails. You can also use C<HTTP::Tiny::can_ssl()> utility function
that returns boolean to see if the required modules are installed.
An C<https> connection may be made via an C<http> proxy that supports the CONNECT
command (i.e. RFC 2817). You may not proxy C<https> via a proxy that itself
requires C<https> to communicate.
SSL provides two distinct capabilities:
TLS/SSL provides two distinct capabilities:
=for :list
* Encrypted communication channel
* Verification of server identity
B<By default, HTTP::Tiny does not verify server identity>.
Server identity verification is controversial and potentially tricky because it
depends on a (usually paid) third-party Certificate Authority (CA) trust model
to validate a certificate as legitimate. This discriminates against servers
with self-signed certificates or certificates signed by free, community-driven
CA's such as L<CAcert.org|http://cacert.org>.
B<By default, HTTP::Tiny verifies server identity>.
By default, HTTP::Tiny does not make any assumptions about your trust model,
threat level or risk tolerance. It just aims to give you an encrypted channel
when you need one.
This was changed in version 0.083 due to security concerns. The previous default
behavior can be enabled by setting C<$ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT}>
to 1.
Setting the C<verify_SSL> attribute to a true value will make HTTP::Tiny verify
that an SSL connection has a valid SSL certificate corresponding to the host
name of the connection and that the SSL certificate has been verified by a CA.
Assuming you trust the CA, this will protect against a L<man-in-the-middle
attack|http://en.wikipedia.org/wiki/Man-in-the-middle_attack>. If you are
concerned about security, you should enable this option.
Verification is done by checking that that the TLS/SSL connection has a valid
certificate corresponding to the host name of the connection and that the
certificate has been verified by a CA. Assuming you trust the CA, this will
protect against L<machine-in-the-middle
attacks|http://en.wikipedia.org/wiki/Machine-in-the-middle_attack>.
Certificate verification requires a file containing trusted CA certificates.
If the environment variable C<SSL_CERT_FILE> is present, HTTP::Tiny
will try to find a CA certificate file in that location.
If the L<Mozilla::CA> module is installed, HTTP::Tiny will use the CA file
included with it as a source of trusted CA's. (This means you trust Mozilla,
the author of Mozilla::CA, the CPAN mirror where you got Mozilla::CA, the
toolchain used to install it, and your operating system security, right?)
included with it as a source of trusted CA's.
If that module is not available, then HTTP::Tiny will search several
system-specific default locations for a CA certificate file:
Expand All @@ -1798,12 +1807,17 @@ system-specific default locations for a CA certificate file:
* /etc/ssl/certs/ca-certificates.crt
* /etc/pki/tls/certs/ca-bundle.crt
* /etc/ssl/ca-bundle.pem
* /etc/openssl/certs/ca-certificates.crt
* /etc/ssl/cert.pem
* /usr/local/share/certs/ca-root-nss.crt
* /etc/pki/tls/cacert.pem
* /etc/certs/ca-certificates.crt
An error will be occur if C<verify_SSL> is true and no CA certificate file
is available.
If you desire complete control over SSL connections, the C<SSL_options> attribute
lets you provide a hash reference that will be passed through to
If you desire complete control over TLS/SSL connections, the C<SSL_options>
attribute lets you provide a hash reference that will be passed through to
C<IO::Socket::SSL::start_SSL()>, overriding any options set by HTTP::Tiny. For
example, to provide your own trusted CA file:
Expand All @@ -1813,7 +1827,7 @@ example, to provide your own trusted CA file:
The C<SSL_options> attribute could also be used for such things as providing a
client certificate for authentication to a server or controlling the choice of
cipher used for the SSL connection. See L<IO::Socket::SSL> documentation for
cipher used for the TLS/SSL connection. See L<IO::Socket::SSL> documentation for
details.
=head1 PROXY SUPPORT
Expand Down
108 changes: 108 additions & 0 deletions t/180_verify_SSL.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!perl

use strict;
use warnings;
use Test::More 0.88;
use lib 't';

use HTTP::Tiny;


{
my $ht = HTTP::Tiny->new();
is($ht->verify_SSL, 1, "verify_SSL is 1 by default");
}

{
my $ht = HTTP::Tiny->new(
verify_SSL => 0
);
is($ht->verify_SSL, 0, "verify_SSL=>0 sets 0");
}

{
my $ht = HTTP::Tiny->new(
verify_ssl => 0
);
is($ht->verify_SSL, 0, "verify_ssl=>0 sets 0");
}

{
my $ht = HTTP::Tiny->new(
verify_SSL => 1,
verify_ssl => 0
);
is($ht->verify_SSL, 1, "verify_SSL=>1 and verify_ssl=>0 sets 1");
}

{
my $ht = HTTP::Tiny->new(
verify_SSL => 0,
verify_ssl => 1
);
is($ht->verify_SSL, 1, "verify_SSL=>0 and verify_ssl=>1 sets 1");
}

{
my $ht = HTTP::Tiny->new(
verify_SSL => 0,
verify_ssl => 0
);
is($ht->verify_SSL, 0, "verify_SSL=>0 and verify_ssl=>0 sets 0");
}

{
local $ENV{PERL_HTTP_TINY_INSECURE_BY_DEFAULT} = "1";
my $ht = HTTP::Tiny->new();
is($ht->verify_SSL, 0, "PERL_HTTP_TINY_INSECURE_BY_DEFAULT=1 changes verify_SSL default to 0");
}

{
local $ENV{PERL_HTTP_TINY_INSECURE_BY_DEFAULT} = "0";
my $ht = HTTP::Tiny->new();
is($ht->verify_SSL, 1, "PERL_HTTP_TINY_INSECURE_BY_DEFAULT=0 keeps verify_SSL default at 1");
}

{
local $ENV{PERL_HTTP_TINY_INSECURE_BY_DEFAULT} = "False";
my $ht = HTTP::Tiny->new();
is($ht->verify_SSL, 1, "Unsupported PERL_HTTP_TINY_INSECURE_BY_DEFAULT=False keeps verify_SSL default at 1");
}

{
local $ENV{PERL_HTTP_TINY_INSECURE_BY_DEFAULT} = "1";
my $ht = HTTP::Tiny->new(verify_SSL=>1);
is($ht->verify_SSL, 1, "PERL_HTTP_TINY_INSECURE_BY_DEFAULT=1 does not override verify_SSL attribute set to 1");
}

{
local $ENV{PERL_HTTP_TINY_INSECURE_BY_DEFAULT} = "1";
my $ht = HTTP::Tiny->new(
verify_SSL => 1,
verify_ssl => 1
);
is($ht->verify_SSL, 1, "PERL_HTTP_TINY_INSECURE_BY_DEFAULT=1, verify_SSL=>1 and verify_ssl=>1 sets 1");
}

{
local $ENV{PERL_HTTP_TINY_INSECURE_BY_DEFAULT} = "1";
my $ht = HTTP::Tiny->new(
verify_SSL => 1,
verify_ssl => 0
);
is($ht->verify_SSL, 1, "PERL_HTTP_TINY_INSECURE_BY_DEFAULT=1, verify_SSL=>1 and verify_ssl=>0 sets 1");
}

{
local $ENV{PERL_HTTP_TINY_INSECURE_BY_DEFAULT} = "1";
my $ht = HTTP::Tiny->new(
verify_SSL => 0,
verify_ssl => 0
);
is($ht->verify_SSL, 0, "PERL_HTTP_TINY_INSECURE_BY_DEFAULT=1, verify_SSL=>0 and verify_ssl=>0 sets 0");
}



done_testing;

0 comments on commit 6cd99f8

Please sign in to comment.