Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSL environment controls, and warn about insecure connections #151

Closed
wants to merge 1 commit into from

Conversation

nrdvana
Copy link

@nrdvana nrdvana commented Feb 21, 2023

This module does not perform host checking on SSL connections by default. This is a major security flaw. I would expect most people to agree with that, but given the rationale in the documentation, it sounds like I need to thoroughly make the case for this change.

Violates RFC

This module claims to be RFC compliant, but RFC 2818 says:

3.1.  Server Identity

   In general, HTTP/TLS requests are generated by dereferencing a URI.
   As a consequence, the hostname for the server is known to the client.
   If the hostname is available, the client MUST check it against the
   server's identity as presented in the server's Certificate message,
   in order to prevent man-in-the-middle attacks.

Since the RFC says "MUST", all users of a "standards compliant HTTP client" should expect that host name checking happens unless they specifically disable it.

There Is No SSL Without Verifying The Certificate

The module documentation describes SSL encryption as being a separate feature from SSL verification, but the encryption offered by SSL is nearly useless without the verification. In almost any case where an attacker has network access to sniff packets of a communication, they also have the ability to conduct man-in-the-middle attacks, and a man-in-the-middle attack negates any value of the encryption. For example, in modern switched Ethernet a host will not see packets unless the packet arrives at the NIC destined for that host's MAC address. If the packet is destined for the host, then the host can just as easily play man-in-the-middle rather than re-broadcasting the packet to the gateway. If the network provider is the attacker, they control the routing of packets anyway. If the government of the internet backbone is the attacker, they also have control over routing, and so on. There is simply no value in SSL if certificate verification is not enabled. In a context where security is not relevant, people should just use plain HTTP since it is faster.

Nobody Reads the Documentation!

Documenting this security flaw is not sufficient, as proven by the CPAN modules using it. Here's a breakdown of what I found in a dozen CPAN modules I picked at semi-random based on how important they sound:

Proposed Change

I think that with 100+ public modules using HTTP::Tiny and a vast majority of them unaware of their security flaw, the greater number of internal applications that will likewise be affected, and even more untold users of those modules and applications who don't realize they have a security flaw, the only responsible thing to do is start emitting a warning from any script affected. I wrote up a patch that does this, emitting one warning the first time an SSL connection is created without any configuration of the verify_SSL attribute.

I have also added two environment variables, one to change the default (so that end users can quickly enable SSL verification, or decide to silence the warning) and a second to override the attribute globally so that when modules start specifying verify_SSL => 1 the end-users who actually need to disable SSL verification still have a way to do so.

My patch does not include unit tests, but if the change is acceptable I will write those next.

The verify_SSL option is disabled by default, which is both a
vulnerability and an RFC 2818 violation.  Being a heavily-used
module by many in-house scripts, it is probably not practical
to change this default, but users need to be warned so that they
can apply whatever security intentions they have rather than
blindly receiving an insecure default.

This patch changes the verify_SSL attribute to remain 'undef'
if the user does not take any steps to assign a value to it.
This condition can then detect cases where an SSL connection
is being established without verification and where the user
did not op-in to this behavior.  It generates one warning
using 'warn', and then suppresses future warnings.

The first new environment variable HTTP_TINY_VERIFY_SSL_DEFAULT
is a boolean that can either opt-in to the default of false, or
change the default to true.  Both settings suppress the warning.

The second environment variable HTTP_TINY_VERIFY_SSL is a
boolean that can override the attribute chosen by users of the
module.  This will become necessary if module authors who use
HTTP::Tiny begin including the (verify_SSL => 1) setting in the
construction of the user agent but end-users of those modules
want to override the decision to allow insecure connections.
This mirrors the utility of PERL_LWP_SSL_VERIFY_HOSTNAME which
end-users can set to quickly permit insecure connections with
LWP::UserAgent.
@nrdvana nrdvana marked this pull request as draft February 21, 2023 05:16
@stigtsp
Copy link
Contributor

stigtsp commented Feb 24, 2023

As you point out, other modules might use HTTP::Tiny from core without knowing about the insecure default, and exposing downstream users to mitm attacks.

This is concerning, and IMHO the default should be changed from 0 to 1 so the modules depending on HTTP::Tiny wouldn't need to be patched.

NixOS has added a patch that does this:

@xdg
Copy link
Collaborator

xdg commented Feb 24, 2023

HTTP::Tiny is very explicit in the list of RFCs that it supports and 2818 is not among that list. The documentation is very clear on the behavior and the rationale for it. You are welcome to create HTTPS::Tiny if you desire.

@xdg xdg closed this Feb 24, 2023
@sjn
Copy link

sjn commented Feb 24, 2023

@xdg What's up with closing this pull request? The addition @nrdvana proposes here is completely reasonable, and in fact the right thing to do. Sure there are bad coding patterns in practice out there, but just shoving these under the carpet to ignore them actively hurts Perl's reputation.

Instead, bad practices should be made visible, and warning about them (like in this pull request) is completely sensible.

Please don't be part of propagating this bad habit.

@xdg
Copy link
Collaborator

xdg commented Feb 24, 2023

This decision was taken a long time and has been discussed extensively since then. Short of the Perl Steering Council directly asking for a change, it's not going to happen.

@sjn
Copy link

sjn commented Feb 24, 2023

Would you mind sharing a link to this decision? Links to previous discussions (or tickets) would also be very much appreciated – both for posterity and right now for those of us following this issue, so we get a clearer idea of existing arguments and facts.

Secondly, it seems you are deferring decisions about this module to the PSC, does this mean you're in favor of them formally taking over management of this module?

Finally – would you mind sharing with us why reconsidering this decision shouldn't be on the table?

@nrdvana
Copy link
Author

nrdvana commented Feb 24, 2023

@xdg What if it had a CVE number assigned to it and all users were forced to apply the patch in order to pass security compliance for their apps? Would that change your mind?

@stigtsp
Copy link
Contributor

stigtsp commented Feb 26, 2023

We've searched CPAN to get an overview of how verify_SSL is used:

  • With HTTP::Tiny, but without verify_SSL: 381
  • With verify_SSL: 65

https://hackeriet.github.io/cpan-http-tiny-overview/

@shadowcat-mst
Copy link

shadowcat-mst commented Feb 28, 2023

@nrdvana @sjn @stigtsp As per the discussion on #134 since this module is shipped as part of core in order to be used to bootstrap a full toolchain, this is something that needs to be discussed by the core and toolchain teams.

I look forward to participating in the perl5-porters thread and irc.perl.org #toolchain discussions about this, after which we can work out whether the documentation should be changed, a warning added if verify_SSL isn't specified (so users have to pick explicitly what affordance they want) or some combination thereof.

Given that reality, this PR is putting the cart before the horse, and actually putting together a patch should wait until the situation has been discussed so it's in line with the resulting consensus - it would be nice if some of the work done for this could be re-used, but under the circumstances there's obviously going to be no guarantee of that.

In the mean time, if anybody wants to improve the current situation, given HTTP::Tiny is designed explicitly for situations where one is forced into minimal dependencies (and hence quite possibly has no CA cert information available at all) arguably the root issue with most of the cpan dists there is that there was never a good reason for them to be using HTTP::Tiny in the first place and patches should be sent replacing it with the full user agent they should have already been using.

@nrdvana
Copy link
Author

nrdvana commented Feb 28, 2023

@shadowcat-mst I started with the reddit post before I realized that it was a core module, and I made this patch next just to be really clear about what I was proposing. (i.e. it does not "break" anything, and doesn't spam people with warnings, just a single targeted blip on stderr for the cases where it matters, and that can be prevented with an environment variable)

I do understand now that perl doesn't ship with CA information, and the module was meant as a bare-minimal http client to make tooling possible. But, 381 CPAN modules have proven that people just really want an in-core https client and that they either don't read the documentation, or don't care about security; it can't help that the module documentation itself seems kind of dismissive about verification like it is nothing more than a money grab by CA companies.

Meanwhile, aside from there being an impractical number of CPAN modules to submit bug reports to (and how do you monitor for future ones?) the big problem is that if these authors do update their code with verify_SSL => 1, there is no way for the end-user to opt-out of the change other than possibly awkward changes to code that they might not be familiar with. There needs to be some quick environment variable like LWP::UserAgent has that lets you connect to in-house stuff that you haven't properly configured the server or the local CA trust store.

@shadowcat-mst
Copy link

@nrdvana I think arguably those distributions prove that people will lazily use in-core modules for stupid reasons, which has sadly been proven repeatedly (I'm going to try not to remember any of the previous examples right now for the sake of my remaining SAN score but ... yeah ...).

Anyway, it's clear this conversation has already gone horribly wrong and that given the issue has come up repeatedly already I think we're better off going discussion-first rather than patch-first, so I've opened #152 to attempt to make a start at that.

@nrdvana
Copy link
Author

nrdvana commented Mar 3, 2023

@shadowcat-mst I'm getting offtopic, but I think those distributions prove that people want a batteries-included perl, and that the module name and documentation failed to communicate that it was a partial implementation rather than a minimalist implementation. Seeing "::Tiny" in a name is generally a good thing and for other modules means that the author has reduced the API to the pure essence of the problem.

gentoo-bot pushed a commit to gentoo/gentoo that referenced this pull request May 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants