First Step with Clojure: Terror

Posted: Thu, 24 July 2014 | permalink | 6 Comments

$ sudo apt-get install -y leiningen
[...]
$ lein new scratch
[...]
$ cd scratch
$ lein repl
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.pom from repository central at http://repo1.maven.org/maven2
Transferring 5K from central
Downloading: org/sonatype/oss/oss-parent/5/oss-parent-5.pom from repository central at http://repo1.maven.org/maven2
Transferring 4K from central
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.jar from repository central at http://repo1.maven.org/maven2
Transferring 3311K from central
[...]

Wait… what? lein downloads some random JARs from a website over HTTP1, with, as far as far I can tell, no verification that what I’m asking for is what I’m getting (has nobody ever heard of Man-in-the-Middle attacks in Maven land?). It downloads a .sha1 file to (presumably) do integrity checking, but that’s no safety net – if I can serve you a dodgy .jar, I can serve you an equally-dodgy .sha1 file, too (also, SHA256 is where all the cool kids are at these days). Finally, jarsigner tells me that there’s no signature on the .jar itself, either.

It gets better, though. The repo1.maven.org site is served by the fastly.net2 pseudo-CDN3, which adds another set of points in the chain which can be subverted to hijack and spoof traffic. More routers, more DNS zones, and more servers.

I’ve seen Debian take a kicking more than once because packages aren’t individually signed, or because packages aren’t served over HTTPS. But at least Debian’s packages can be verified by chaining to a signature made by a well-known, widely-distributed key, signed by two Debian Developers with very well-connected keys.

This repository, on the other hand… oy gevalt. There are OpenPGP (GPG) signatures available for each package (tack .asc onto the end of the .jar URL), but no attempt was made to download the signatures for the .jar I downloaded. Even if the signature was downloaded and checked, there’s no way for me (or anyone) to trust the signature – the signature was made by a key that’s signed by one other key, which itself has no signatures. If I were an attacker, it wouldn’t be hard for me to replace that key chain with one of my own devising.

Even ignoring everyone living behind a government- or company-run intercepting proxy, and everyone using public wifi, it’s pretty well common knowledge by now (thanks to Edward Snowden) that playing silly-buggers with Internet traffic isn’t hard to do, and there’s no shortage of evidence that it is, in fact, done on a routine basis by all manner of people. Serving up executable code to a large number of people, in that threat environment, with no way for them to have any reasonable assurance that code is trustworthy, is very disappointing.

Please, for the good of the Internet, improve your act, Maven. Putting HTTPS on your distribution would be a bare minimum. There are attacks on SSL, sure, but they’re a lot harder to pull off than sitting on public wifi hijacking TCP connections. Far better would be to start mandating signatures, requiring signature checks to pass, and having all signatures chain to a well-known, widely-trusted, and properly secured trust root. Signing all keys that are allowed to upload to maven.org with a “maven.org distribution root” key (itself kept in hardware and only used offline), and then verifying that all signatures chain to that key, wouldn’t be insanely difficult, and would greatly improve the security of the software supply chain. Sure, it wouldn’t be perfect, but don’t make the perfect the enemy of the good. Cost-effective improvements are possible here.

Yes, security is hard. But you don’t get to ignore it just because of that, when you’re creating an attractive nuisance for anyone who wants to own up a whole passel of machines by slipping some dodgy code into a widely-used package.


  1. To add insult to injury, it appears to ignore my http_proxy environment variable, and the repo1.maven.org server returns plain-text error responses with Content-Type: text/xml. But at this point, that’s just icing on the shit cake.

  2. At one point in the past, my then-employer (a hosting provider) blocked Fastly’s caching servers from their network because they took down a customer site with a massive number of requests to a single resource, and the incoming request traffic was indistinguishable from a botnet-sourced DDoS attack. The requests were coming from IP space registered to a number of different ISPs, with no distinguishing rDNS (184-106-82-243.static.cloud-ips.com doesn’t help me to distinguish between “I’m a professionally-run distributed proxy” and “I’m a pwned box here to hammer your site into the ground”).

  3. Pretty much all of the new breed of so-called CDNs aren’t actually pro-actively distributing content, they’re just proxies. That isn’t a bad thing, per se, but I rather dislike the far-too-common practice of installing varnish (and perhaps mod_pagespeed, if they’re providing “advanced” capabilities) on a couple of AWS instances, and hanging out your shingle as a CDN. I prefer a bit of truth in my advertising.


6 Comments

From: Jan Hudec
2014-07-24 18:17

For downloading package dependencies it would also be possible to have the package itself include the keys that the dependencies are expected to be signed with (or have valid signature chain to). It would put additional responsibility on authors of the packages, but they kind of have it already, and would have the advantage that it would work for downloading from anywhere on the web. And would also limit possible damage if somebody used a strawperson with key signed by the central root.

Allowing a key to which a valid signature chain exists is important to allow handing over maintenance. Our company recently sold a product for Android and we had to give them the key as well, because Android does not have any mechanism for rekeying a package. Kind of kills the security. So allowing rekeying by the old author signing key of the new author would be needed. As a side-effect it would allow the authors to list root key of the maven repository if it indeed was created.

From: Tollef Fog Heen
2014-07-24 21:19

Not disagreeing at all with the main point in the article, but wanted to add a few clarifications about CDNs (since that’s something I care about). (Also, in the interest of full disclosure, I should tell that I work for Fastly.)

You shouldn’t trust reverse DNS for who owns a netblock, you should rather look it up in whois. Your example doesn’t resolve, but would resolve to a rackspace IP where I don’t believe we have ever hosted cache servers. We have also run our own netblocks for quite some time, so while it might have been true in the past that there wasn’t the necessary information in whois that’s long since been fixed.

I know you’re not claiming directly that we’re hosted on EC2, but it’s not an unreasonable reading of what you write and we’re absolutely not. I don’t think they do servers of the class we run (18T SSDs, 768G RAM, 4x10GE NICs). While you might require a CDN to not support origin pull, that is a pretty uncommon interpretation.

From: Anonymous
2014-07-25 13:30

This seems like a pervasive problem with languages that think themselves important enough to have a packaging system. I don’t want your packaging system, I have apt already.

From: Phil
2014-07-26 05:39

Please don’t use the version of Leiningen in apt; it’s very old and missing all the signature verification and proxy features you’re complaining about.

Maven Central offers SSL, but only to users who make a donation: http://blog.sonatype.com/2012/10/now-available-ssl-connectivity-to-central/ which is terrible but not as terrible as you’ve made it out to be.

From: Matt Palmer
2014-07-27 16:10

Jan, don’t get me on the Android security model. I actually think the way they use keys in that model is the least of the problems – but certainly, using one key to sign all your packages, and then not permitting rekeying, does make it impossible to hand off one package out of several without giving away the family silver.

Tollef, the example I gave was pulled directly from an IRC conversation with Fastly staff, at the time the incident occured. Fastly did host machines in Rackspace IP space, as well as in Cogent IP space. Neither block was SWIP’d to Fastly, either – I do know how to whois.

Phil, thanks for chiming in to remind us that the leiningen in Debian is painfully old. I’ll pop over to my soapbox to respond to the rest of your points…

I’m afraid the current version of Leiningen doesn’t address my complaints in any satisfactory way. While the components downloaded via HTTP do use the proxy now, there’s still no signature checking being done anywhere. I can’t see anywhere in the lein script that is downloading the .asc signature file that is associated with the .jar file in the Github release – although I chuckled when I saw the “TODO: checksum” comment. The key that made the signature associated with the Github release at least has a few signatures on it, but gpg doesn’t want to tell me whether or not there’s a decent trust path between us because the key expired a week or so ago (whoops).

No .asc files for any of the .pom or .jar files downloaded from repo1.maven.org were downloaded, either. Even if they were, I suspect there’s still no guaranteed way to verify trust in the keys that made the signatures.

As for SSL: I will admit that SSL is significantly better than not checking signatures made by untrustable, expired keys. However, Fastly’s doing SSL interception (with a “here’s all our clients!” SSL cert – good work, fellas!).. That’s a place where content that should be secure could be intercepted, and there’s no way to verify the way by which traffic got from maven.org to Fastly – you’d hope it was, itself, SSL-secured, but we’ve got to take that on faith. Also, only providing SSL to people who pay seems… well, let’s just say that my thoughts on the matter contain a lot of profanity. Then there’s the issue that data at rest is susceptible to tampering by intruders, and SSL only protects data in transit…

SSL is great as far as it goes (transport integrity and confidentiality), but I’m not convinced it is sufficient for the purpose of ensuring software package integrity.

From: Thomas Koch
2014-07-29 07:03

Welcome to the world of the Java! Java is business and business gives a shit on security. I tried to encourage people in the Apache Foundation (host of many important java projects) or on Java conferences to do keysigning… Nobody cares.

Post a comment

All comments are held for moderation; markdown formatting accepted.

This is a honeypot form. Do not use this form unless you want to get your IP address blacklisted. Use the second form below for comments.
Name: (required)
E-mail: (required, not published)
Website: (optional)
Name: (required)
E-mail: (required, not published)
Website: (optional)