I love working with composer. I think it’s a really neat way of dealing with dependencies in (PHP) projects and it’s not for nothing that big frameworks like symfony2 are using composer as their primary way of handling bundles and other components. But this blogpost is not about problems with composer (well, not really anyway). It’s about installing composer. It is fundamentally wrong, and it sets a very, very bad precedent for both experienced and inexperienced (php) developers.
As found in the installation manual, installing composer on your system is very easy:
$ curl -s https://getcomposer.org/installer | php
Just run this command on your system, and composer is automatically up and running to its lastest version. Couldn’t be easier right? Well, not quite, but the idea is ok: don’t let the user worry about installing stuff, just run this command and – magically – you have the latest version of composer directly to your disposal. That’s fair enough, and I completely understand this reasoning, developers want to develop, not to do system administration.But even though this system is created with the best intentions, it’s absolutely the wrong way(tm) and sets some bad precedences, especially for developers who aren’t that into system administration.
So what’s wrong?
Michael Maclean has written a very good article on what is wrong with this. His point essentially boils down to this: you have no way of knowing what you are actually installing on your system and if it’s the software as intended by the original developers. Especially developers tend to do this more and more often, and in even more dangerous ways.
Now, this is bad by itself of course, but this is not a simple app you run on occasion (if that was an excuse to begin with). Composer is the software that pretty much controls ALL your application dependencies. What would happen if this software would fetch its packages from packagists.org, or packagits.org? Would you be able to spot this, even if the rest of the composer code looks similar? The thing is, backdoors and exploits aren’t just simple functions called “exploit” or “backdoor”. They are mostly well-hidden in parts of the code or algorithm that on first glance doesn’t seem anything wrong with. If such backdoor or exploit was obvious people already have found it and even then, they can do a lot of damage without anyone knowing about it for a long time.
Now, let’s suppose the getcomposer.org website gets hacked, or better, the server it’s running on and somebody planted a different version of the composer installer (or even composer application itself). What are our safeguards against this? There are no md5 and sha256 sums of the software on the site (At 12 october 2012, around 21:10 (CET), I’ve downloaded the contents of https://getcomposer.org/installer. The sha256 for this file is d169d6bba1b5f1bb0e6113ed08bbde12fc3ac0b9d95351ff2013350cd247fd9c, and it’s md5sum 7f4a28eafcfc0495db4d1bd48db614d8). But even if they were present, how do we know for sure that those hashes are indeed the hashes from the software the developers originally intended? In short: you cannot know for sure, and every (automated) system is sooner or later based on a trust issue. Do you trust developers to take care of their software: probably. Do you trust ANY link between the developers and your system, including the hardware they run their platform on and all the users that may have access (legal or illegal) to those system? I do not.
And this is a “good thing”. If I put trust in a developer by downloading their software, both I and them want to be 100% sure that I actually get the software they released and not some “modified” version by a third “evil” party . And the nice part about this: this is easy to check since 95% of the software running on my systems are installed through package managers which signs the packages. That way, i do not have to worry about the fact if a package downloaded is really the package that the developer/packager intended. I know that for sure, otherwise the signature of the package would differ. Now, changing a signature isn’t easy. In fact, it’s really hard. Either you have to figure out a way to create a package that has the same md5sum or (but preferably and) sha526 sum, plus maybe some other information, like the package size in bytes. That’s one way to do it. Another way is to create a new signature which only the original packager can do through it’s private key. If you want to know more about public/private key encryption and signing, I do lots of presentations at conferences about this subject. Ultimately, this system too is running on trust, but it’s a much more easier and viable trust system that is pretty much impossible to defeat (although it can be done of course).
Now, every time I “need” to install composer by piping some downloaded code from the internet through the PHP interpreter, I like to rant about it on twitter.I feel dirty doing it, so I don’t. I download the software, do a quick check and THEN run it through PHP. There is not much I cannot do to validate it. I don’t do auto updates since it basically does the same thing internally. And these twitter rants spark lots of discussion on occasion. I like that, because for one I like to troll :p, but it’s also good because it gets people to think about the problem even though they don’t see it at first. And I hear lots of non-solutions for the problem, mostly because people heard that the solution has got to do with security. Two of the major ones: “It’s got SSL now”, and “just don’t run as root“. First of all, SSL solves nothing. I still can get another site up that looks like composer AND get a certificate for that AND it’s still SSL. SSL (TLS, to be exact), encrypts the communication between a server and a client so snooping and man-in-the-middle attacks are not possible. But this is all moot when the software on the server is wrong to begin with. So it definitely doesn’t solve our problem, except that people cannot see what i’m downloading from getcomposer.org or packagist.org, but i don’t really care since it’s not sensitive data to begin with! However, it’s always good practice to have SSL/TLS running on your sites no matter what, but solving the problem: it doesn’t..
The other issue, “don’t run as root” is also pretty invalid. I agree, that it will make evil-doers’ lives much easier if we actually installed it as root. But local exploits are available on many systems and without knowing what is being run, changes you might as well running such a local exploit that escalates your privileges to root, and installs a rootkit or two, and THEN just do it’s standard composer stuff. For all you know, it was running properly on your system. So yes, good advice, but given for the wrong problem.
So some followers like me to stop ranting and start fixing, but this is a more deeper problem than issuing a quick fix. It’s about setting a precedent here. The PHP community isn’t really well known for its high quality software and security achievements. It took years to get rid of the “laughing stock of the internet” status and to be accepted as a solid environment for web applications and mission critical apps. We all know it is, but the “outside” still is on the fence about this one. By having a high-profile application saying: it’s allright to do stuff this way, we are creating a precedent that we don’t really care about security. Just download stuff on the internet and run it.. you’ll be fine.. after all: what could possibly go wrong?
Implementing a fix
So, signing is our solution. How do we implement this? The best way: get composer as soon as possible into main distribution package lines just like php, pear and other systems. At that point signing is automatically taken care of and we at least we know it’s the correct code that the developer intended.
Also, get rid of auto-update, since they are basically the same thing. If software is changing that much, i would not consider it stable enough to be release in the first place. And though continuos deployment is hip and trendy at the moment, this isn’t the place to do this. Fix security leaks straight away, collect features and release your software just like any other application. Again, if people continuously need the latest version, your software wasn’t stable enough to be released.
As a quick fix: Create composer RPM,DEB packages (they are noarch, so we don’t have to worry about that), which are automatically signed and checked for. All we need to import and trust the signer’s key (and the GPG web-of-trust system is awesome enough to have you covered). We can even create signed tarballs and you can even create signed copies of your git-tags. But unless this is automatically checked, most won’t bother and that’s fine. And i’m the first to admit that I too am lazy most of the time and run unchecked, unverified and unsigned code. But at least at that point it is my choice and my responsibility. Composer at this time forces me into running unchecked, unverified and unsigned code, which is where I really draw the line.
For the packages on packagist itself: only export signed tags which can automatically be compared against the authors public key. Even though it can still contain bad code, at least we are certain that the code that is begin downloaded onto my system is actually the code that is signed off by the developer. But we need to think about the consequences.. And I know, it’s easy to preach security, and I’m the first to admin I too download stuff, don’t check it and hope for the best.. but let’s agree that we at least we have a choice here, and composer does not give us this choice unfortunately.
I know, it doesn’t give you a 100% waterproof secure way of installing the software, but it’s as good as it gets without physically and manually very the code with the developers. It’s the way we deal with our distribution’s packages, with pretty much EVERY SSL certificate where you have placed your trust in somebody you do not know added their consent into a SSL certificate of your bank, your favorite ecommerce-site, and every other HTTPS powered website.
So let me rephrase once again: I like composer. It serves a purpose and it serves it well and I really enjoy it compared to other dependency systems. And I understand it’s still not “there yet” and many things will change in the next couple of months probably. But we have to make a stand against software that teaches bad practices and tell them how we can things. Hopefully this will clear a thing or two up.