SSL security in HTTP::Tiny

I was asked to add SSL support to a client library, while also moving from home-grown manual HTTP code to a proper module. HTTP::Tiny was ideal because it is pure-Perl, a core module since 5.14 (so it’ll be maintained), and it’s just one .pm file, making it easy to ship.

An application server that supported SSL was provided for testing purposes, but the SSL certificate didn’t match the hostname – HTTP::Tiny correctly rejected connections. I needed to be able to control the settings sent to the underlying IO::Socket::SSL object used for the encrypted connection so I could turn off security features for testing. As I worked on that, David Golden offered invaluable feedback, which greatly improved the design of the features added to HTTP::Tiny.

As of 0.018, HTTP::Tiny is more configurable, and has a simple interface for easily making SSL connections more secure.

By default, HTTP::Tiny can’t do SSL at all, but if you install IO::Socket::SSL, it can. Unfortunately, even with that, the SSL connection will be insecure – no checking is done that the SSL certificate’s CN matches the hostname of the server we’re connecting to, nor is it checked for validity according to a Certificate Authority. But now, you can add

verify_ssl => 1
to the constructor to get more secure operation. The hostname will be validated, and we’ll try to find a CA bundle to verify the server’s certificate with. It is recommended to install Mozilla::CA, which provides a CA bundle, but we’ll try to find the file your operating system provides if possible. If none are found, it is a fatal error, so installing Mozilla::CA is probably a good idea.

If you need finer control (SSL client certs, verifying the hostname but not verifying against a CA bundle, providing your own validation callback), you can pass SSL_options in the HTTP::Tiny constructor, and those SSL_* options will get passed to IO::Socket::SSL::start_SSL. It’s not recommended to do that unless you know what you’re doing – and that’s harder than you think. The documentation is atrocious, but I think we’ve done a good job of hiding the best and most common security settings behind verify_ssl => 1.

TLDR: If you want SSL using HTTP::Tiny to be secure, install HTTP::Tiny version 0.018, IO::Socket::SSL and Mozilla::CA; and use verify_ssl => 1 in HTTP::Tiny's constructor.

Lessons learned

This episode has made me wonder why Perl doesn’t provide SSL support out-of-the-box. You need an add-on to make it work - and not just any add-on. IO::Socket::SSL is actually not trivial to deploy. You need OpenSSL libraries installed, which requires a compiler. There are systems where that is the end of the road. Maybe you don’t support them, but someone does. Unfortunately, the servers running 5.004000 probably aren’t updating to 5.020000 any time soon, having SSL available in the core install would be a good first step for Perl’s next decade.