Add an “S” to the end of HTTP and you get an encrypted channel using HTTPS. Add an “S” to the front of SSL and you get a Sometimes Secure Sockets Layer. Mix in a mobile app. Watch how HTTPS everywhere becomes HTTPS nowhere.
One important piece of the “secure” in the Secure Sockets Layer protocol is the trust it establishes in identifying an end point. If a server’s certificate has an error — it’s improperly signed, it’s expired, the domain names are mismatched — then the browser cries out in alarm that something is amiss. Actually, this cry tended to be an annoying peep for the longest time, but browsers have since turned it into a raging klaxon.
Now consider mobile apps that make their own HTTPS connections, or web apps that need to call out to other servers over HTTPS. The code to do this has to come from somewhere other than a browser. And far too many developers fail the Ice Cube test:
Check yo self before you wreck yo self
That’s right, they don’t bother to verify the remote certificate, throwing away the entire purpose of the identity check for an HTTPS connection. What’s the point of requiring an encrypted connection if you don’t care who intercepts the connection securely? Those developers have ignored the benefits of Ice Cube’s uncomplicated wisdom. Make them listen to The Predator, track 13. And toss in a movie night with Friday or, my preference, Ghosts of Mars (after all, I’m partial to John Carpenter movies) — which also features the ever-badass Pam Grier.
I’ve alluded to this non-verification problem in the past, both in the book and in presentations. One collection of examples came from a now long-removed list of OAuth example code on Twitter’s developer resources. (The page pointed to third-party libraries with usual disclaimers of non-endorsement and non-guarantees. Twitter’s only to blame for poor vetting and a lack of quality reference implementations.) My observation was that this was a problem endemic to programming, not a specific programming language. And that the growth of mobile apps and “browser-like” clients that aren’t, in fact, browsers would compound the problem.
Recently, researchers have more explicitly quantified the problem in a well-written paper, The Most Dangerous Code in the World. (Hyperbole, perhaps, but attention-grabbing.) The abstract lays out the serious danger they enumerated from various source code:
We demonstrate that SSL certificate validation is completely broken in many security-critical applications and libraries. Vulnerable software includes Amazon’s EC2 Java library and all cloud clients based on it; Amazon’s and PayPal’s merchant SDKs responsible for transmitting payment details from e-commerce sites to payment gateways; integrated shopping carts such as osCommerce, ZenCart, Ubercart, and PrestaShop; AdMob code used by mobile websites; Chase mobile banking and several other Android apps and libraries; Java Web-services middleware—including Apache Axis, Axis 2, Codehaus XFire, and Pusher library for Android—and all applications employing this middleware. Any SSL connection from any of these programs is insecure against a man-in-the-middle attack.
In addition to the paper, the link includes brief background information on the problem and some tools to help identify this kind of error.
I’ll close with a short exercise for the reader. Consider the problem posed by the libcurl API as mentioned in the paper. Two functions share a similar naming scheme, but take very different argument types. One accepts a Boolean, the other accepts an integer. Easy question: How would you modify the API? Hard question: How would you modify the API without breaking (admittedly broken) software that relies on a pervasive and popular library?
I’ve mentioned libcurl favorably in the past, especially the helpfulness of its mailing list. It has a smart developer community. It’s one of the longer-running open source efforts that’s actively maintained and growing. They went through a long discussion on the best way to resolve the problem given their restraints of preserving compatibility.
To prompt your own thoughts on the subject, look at the problem as a confusion within design and language (as in written, not programming, language). A characteristic of a good API is preciseness in naming. In this case, the “verify” in “verifyhost” implies a binary action, especially when another “verify” function (verifypeer) is explicitly Boolean.
If the API intended the verification method to offer a choice among several options, a better name might have been “verifyhoststrategy”. That’s a pretty awkward name and a pedantic arguer might claim “verify” still implies a true/false choice.
A minor tweak could be “verificationstrategy”, although it turns the verb into a noun. If your API demands every method begin with a verb, then “useverificationstrategy” may suffice. In any case, you’re relying on developers to make a minimal effort to understand the method and its arguments.
It’s hard to beat browsers at the security game. HTTP Strict Transport Security (HSTS) rejects invalid certs. It’s a great way to make your site more secure from sniffing and interception attacks with burdening the user with decisions. HTML5’s WebSocket API refuses to establish wss: (i.e. SSL/TLS) connections if it encounters cert errors; it doesn’t even give the user a chance to declare an exception.
If an extra “S” in SSL means Sometimes, then it’s probably because you’ve invoked an “L” that means library. And think about what Ice Cube might say about to developers using a third-party library: RTFM.