Composer and Packagist - a bad implementation!

Published on 2015-12-10. Modified on 2016-08-07.

On many websites, in a huge amount of Github projects, and in several books, like the book 'Modern PHP, New Features and Good Practices' by John Lockhart, so-called 'modern PHP' is made synonymous to using Composer and Packagist in combination with the usage of the recommendations provided by the PHP-FIG. Lots of people follow these advices almost blindly, but the reality is that this is NOT good practice from a security stand point.

Update 2016: Composer has since the writing of this article implemented a public key signing procedure in order to deal with one of the problems described below. However, that doesn't solve the problem. When you verify a signed file you check the signature against a public key. The question is: which public key? And therein lies the problem. Composer doesn't have a well defined model of trust and all they have achieved is to thrown cryptography at the issue in order to give people the impression that their system has signature verification.

In the world of PHP, well in a large part of the community anyways, Composer has almost become a de facto standard way of dealing with third party libraries. Composer is propagated on websites and in books as "the way you SHOULD deal with components". Composer is a package and dependency manager for PHP. It makes it simpler to include third-party code just by adding a few lines to a composer.json configuration file.

Don't get me wrong, Composer IS really great! However, the current implementation lacks good security practice so you need to be careful using it.

One line installer

One of the main problems with Composer is the installation itself. It sets a bad example for developers and it is a fundamentally flawed way of doing things.

On the https://getcomposer.org/download/ website you'll find (as of writing) the following instructions:

Run this in your terminal to get the latest Composer version:

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === 'e115a8dc7871f15d853148a7fbac7da27d6c0030b848d9b3dc09e2a0388afed865e6a3d6b3c0fad45c48e2b5fc1196ae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

So you now verify Composer's signature against a public key using a SHA384, but the problem is this: How do you know you can trust that public key? You're blindly assuming that the code you get from getcomposer.org and the public key is actually coming from the original authors. Since there doesn't exist a well defined model of trust, you cannot know who is giving you the key!

That's also why it makes absolutely no sense when people randomly put their public GPG keys up for usage on their websites without any other means of verification. All an attacker needs to do is to exchange the public key with a key of his own. Without a well defined model of trust - such as a Web of Trust for example - key signing is completely useless.

If the website getcomposer.org is ever compromised and their public keys are changed, you could be installing anything!

Something similar happened when Hackers Compromised the Download Link for Linux Mint with a Backdoor.

This is a serious issue in itself, but because Composer is the application that controls all your application dependencies, the problem becomes even worse. What's going to happen if Composer starts fetching software from an evil source?

Backdoors and exploits are mostly well-hidden parts of code that might even appear as simple coding mistakes. Such exploits can do a lot of damage without anyone knowing about it for a very long time.

Using hashes (no matter what kind) doesn't provide any kind of security against this. If the application itself is compromised then surely the hash would be too.

It's got SSL!
It isn't run as root!
Don't use it directly on production machines!

These are some of the replies I got when I raised my concerns about these problems with Composer. But these replies unfortunately only serve to demonstrate the ignorance about the importance of the issue. SSL only encrypts the communication between the server and the client, it can do absolutely nothing for you if the software you're about to download has been compromised.

Not running the application as root is a given, really, who would do that nowadays? But that doesn't solve the issue. If we assume that Composer has been compromised then all that's needed is an exploit that escalates privileges to root, installs a back door or a rootkit, and then continues to function normally.

Running it only locally and not on production may seem to solve at least some problems, but if Composer itself is compromised you don't know what it is doing, it doesn't even have to pull stuff in from an evil source. A compromised package manager dealing with source code can be built to work as the original package manager. It can then have the added feature that it looks for specific dependencies only, say like a popular Symfony component. Once such a component is downloaded the compromised package manager then change a small piece of the source code of that particular component (a simple search and replace would do), leaving it almost identical to the original component, but now with an added exploit. Once you move the software from your local machine to production you're exposing your application to a serious security issue.

No package signing

Packagist is the main Composer repository. It aggregates public PHP packages installable with Composer. It does this without any kind of package signing whatsoever.

With packaging systems such as apt from Debian or pkg_add from OpenBSD, there are cryptographic signatures attached to each and every package that gets installed and there exists a well defined model of trust. These sign each release of the package in question, and hence there is a layer of trust you can use to help decide if you really wish to use the package.

For many years the PHP community has been a laughing stock in the security industry due to the extreme lack of security awareness amongst PHP developers. Chris Shiflett, OWASP, and a bunch of other people have really helped improve the situation a lot by making PHP developers aware of these issues, however with the release of Composer and Packagist the PHP community is heading in the wrong direction.

Composer and Packagist works by pulling code from GitHub repositories. In between there is no security audit whatsoever and nobody is making sure that open security bugs have been fixed before you download them. You need to run through all the code to verify that it doesn't contain any "known issues", but this also means that you must have the necessary skills to do so.

On a Linux distribution like Debian, or on a BSD project like FreeBSD, we have security experts that do their very best to ensure that the package managers don't ship out third party software with known security issues. Packages are swiftly upgraded with security patches or at least a warning is issued. However, even in these circumstances you're still advised against installing third party code that don't get any serious security handling by the authors.

In a lot of the packages you'll find on Packagist, third-party code is pulled in as dependencies and then these dependencies themselves has other dependencies and it is extremely easy to get into a form of "dependency hell". Every time a dependency gets pulled in you increase the risk of exposing your application to a serious security issue or bug. You also now have to review code many levels deep to ensure security.

Of course using third party code always presents a risk, but many different measures needs to be put in place in order to minimize such risk - especially on web development. Using an application that implements none is definitely not the right approach.

You could argue that using a well known third party application is less likely to impose a security risk than running with your own software, and that might be the case if that was the only issue here, but it isn't. The risk of running such a third party library is increased many fold using the above so-called "modern PHP way" of doing things.

Some people have tried to mend some of the issues above. Fabien Potencier announced The PHP Security Advisories Database last year. But as it is stated on the Github page for the project:

This database must not serve as the primary source of information for security issues, it is not authoritative for any referenced software, but it allows to centralize information for convenience and easy consumption.

Which means that this really isn't a solution. Further, it is still possible to install and run harmful applications before any verification has been performed.

Of course projects like Composer needs to start somewhere, but that's not the issue. Everyone - especially people in the PHP community - should have learned the hard way that you really need to take security serious from the very first step in the design process.

More than that, while I fully understand the enthusiasm of some people about Composer and Packagist, advocating this as "modern PHP" without telling people about these problems is bad. People need to be made aware of the possible implications of these issues.

I have noticed that the latest "trends" and so-called "modern ways" of doing things in the PHP community are being propagated very actively all over the Internet and in new books mainly by people with heavy involvement in the PHP-FIG. This makes it even worse as many PHP developers - for some reason - have begun to blindly follow the views expressed by members of the PHP-FIG.

We always need to take security issues serious!

Further reading: